How to calculate childAspectRatio for GridView.builder in flutter - flutter

Grid of categories with image and category name displayed below the image
Widget build(BuildContext context) {
return FutureBuilder(
future: categoriesService.getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
print('error ${snapshot.error}');
return Text(snapshot.error.toString());
}
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
// childAspectRatio: 19 / 12,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Text(category.name)
],
);
},
),
);
} else {
return new CircularProgressIndicator();
}
});
}
My child item has an image and category name. as seen in the image, currently child item is overflowing and we cant see the category name below the image, and unable to remove top space between image and border.
Original design is here

You could use the width and height of the device to calculate the aspect ratio dynamically. I have added a code sample based on yours showing how this could be done. Please note that you might need to adjust the provided aspect ratio slightly in order to fit your particular requirements.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Category {
String name;
String image;
Category({this.name, this.image,});
}
class CategoriesService {
Future<List<Category>> getCategories(int value) async {
return <Category>[
Category(
name: 'FRESH CHICKEN',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FRESH MUTTON',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'HALAL FROZEN FISH',
image: 'https://picsum.photos/400/300',
),
Category(
name: '2X STORE',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN NONVEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN VEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DAL & PULSES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'SPICES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DRY FRUITS & NUTS',
image: 'https://picsum.photos/400/300',
),
];
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: CategoriesService().getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
print('error ${snapshot.error}');
return Text(snapshot.error.toString());
}
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Padding(
padding: const EdgeInsets.only(
top: 8.0,
),
child: Text(
category.name,
textAlign: TextAlign.center,
),
)
],
);
},
),
);
} else {
return new CircularProgressIndicator();
}
}),
),
);
}
}
You might find the below answers useful for additional information regarding the aspect ratio of the GridView widget if you have not seen them already.
How to set Custom height for Widget in GridView in Flutter?
How to set grid view column height?
flutter how to give height to the childrens of GridView.Builder

I find a way to set aspect ratio of biggest child to our Grid view dynamicly.
how it work ?
First please Look at this answer for . how we can find size of a widget during the build with overlayEntery
How to get a height of a Widget?
after that we set the right aspect ratio (Measured with overlayEntery ) to our Grid View in childAspectRatio.
I hope this help you .
I Make an Example ...
https://dartpad.dev/4821d71ec618d7d1f1f92f27458fde61
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class GridItemModel {
String longtext;
GlobalKey itemKey;
double width;
double height;
GridItemModel(this.longtext) {
itemKey = GlobalKey();
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return _StateHomePage();
}
}
class _StateHomePage extends State<MyHomePage> {
// this first assign very important don't change it .
// if you change this part overlayEntry cant find biggest widget correctly .(cant see not scrolled items.)
// for test change to 1/1 and see what happening.
var myDynamicAspectRatio = 1000 / 1;
OverlayEntry sticky;
List<GridItemModel> myGridList = new List();
double maxHeight = 0;
double maxWidth = 0;
#override
void initState() {
if (sticky != null) {
sticky.remove();
}
sticky = OverlayEntry(
builder: (context) => stickyBuilder(context),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
Overlay.of(context).insert(sticky);
setState(() {});
});
super.initState();
}
#override
void dispose() {
WidgetsBinding.instance.addPostFrameCallback((_) {
sticky.remove();
});
super.dispose();
}
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: GridView.count(
crossAxisCount: 2,
childAspectRatio: myDynamicAspectRatio,
children: List.generate(20, (index) {
myGridList.add(new GridItemModel(longTextMaker(index)));
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
key: myGridList[index].itemKey,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
color: Colors.teal[index*100]
),
child: Text(
'Item $index' + myGridList[index].longtext,
style: Theme.of(context).textTheme.headline5,
),
),
],
);
}),
),
),
);
}
String longTextMaker(int count){
String result = "longText";
for(int i = 0 ; i < count; i++){
result += "longText" ;
}
return result;
}
shouldUpdateGridList(){
bool isChanged =false;
for(GridItemModel gi in myGridList) {
if(gi.width != null) {
if (gi.height > maxHeight) {
maxHeight = gi.height;
maxWidth = gi.width;
isChanged = true;
}
}
}
if(isChanged) {
myDynamicAspectRatio = maxWidth / maxHeight;
print("AspectRatio" + myDynamicAspectRatio.toString());
}
}
Widget stickyBuilder(BuildContext context) {
for(GridItemModel gi in myGridList) {
if(gi.width == null) {
final keyContext = gi.itemKey.currentContext;
if (keyContext != null) {
final box = keyContext.findRenderObject() as RenderBox;
print(box.size.height);
print(box.size.width);
gi.width = box.size.width;
gi.height = box.size.height;
}
}
}
shouldUpdateGridList();
return Container();
}
}

Child aspect ratio is basically width/height of the grid relative to the device.
So let's say you want the width of each grid to be 30 and the height to be 20, you would set the aspect ratio to be 3/2.
I suggest you watch this video directly from the Flutter team. Although its about the AspectRatio widget, the part about setting the aspectRatio applies to this problem

You can provide childAspectRatio in GridView.builder like this:
GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:3,childAspectRatio: (150.0 / 220.0)
)
)

There is a flutter package that solves this problem conveniently. Check it out at https://pub.dev/packages/dynamic_height_grid_view. With this you can specify cross-axis count without respecting aspect ratio.

For most use-cases where child height is static or need to be static,
please use mainAxisExtent.
Official docs
/// The extent of each tile in the main axis. If provided it would define the
/// logical pixels taken by each tile in the main-axis.
///
/// If null, [childAspectRatio] is used instead.
final double? mainAxisExtent;

The childAspectRatio value is a value for you to set the aspect ratio, if you want to make a neat square, you would use 1 and the width will be equal to the height.
if you want it to extend to the bottom, decrease the value.
sample
childAspectRatio:0.9,

Try this
return LayoutBuilder(builder: (context, constraints) {
return GridView.count(
crossAxisCount: crossAxisCount( constraints.maxWidth,100),
)
};
);
int crossAxisCount(double maxWidth, size) {
int width= maxWidth~/ size;
return width== 0 ? 1 : width;
}

(ScreenWidth - (left&right Padding + crossAxisSpace))/ itemHeight
Eg.
I have an item with height 241
and gridview padding of left and right => 16 + 16
and crossAxisSpace 9
I will calculate like this
double extraSpace = (16+16+9);
aspectRatio : ((MediaQuery.of(context).size.width - extraSpace) / 2) / 241

Related

Flutter ListView.builder renders items in top-left corner

I need list view builder to generate tiles based on the number of documents there will be in firebase for now I am just trying to sort the UI. I dont understand why its breaking. Image 1 is when the ListView.buidler is commented out. Image 2 is leaving ListView in.
List item
import 'package:flutter/material.dart';
import 'package:track/src/widgets/admin_navbar.dart' as widgets;
import 'package:track/src/widgets/colour_icon_button.dart' as widgets;
import 'package:track/src/features/clients/domain/client_firebase_storage.dart';
class ClientsPage extends StatefulWidget {
const ClientsPage({Key? key}) : super(key: key);
#override
State<ClientsPage> createState() => _ClientsPageState();
}
class _ClientsPageState extends State<ClientsPage> {
late final ClientFirebaseStorage _clientsService;
late double screenWidth;
late double screenHeight;
#override
void initState() {
_clientsService = ClientFirebaseStorage();
super.initState();
}
#override
Widget build(BuildContext context) {
screenWidth = MediaQuery.of(context).size.width;
screenHeight = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: const FlutterLogo(),
),
drawer: const widgets.AdminNavBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Clients',
style: Theme.of(context).textTheme.headline1,
),
const SizedBox(
width: 30,
),
const widgets.ColourIconButton(icon: Icon(Icons.search_rounded)),
const SizedBox(
width: 5,
),
const widgets.ColourIconButton(
icon: Icon(Icons.swap_vert_rounded),
),
SizedBox(
width: screenWidth - 350,
),
const widgets.ColourIconButton(
icon: Icon(Icons.add),
),
],
),
SizedBox(
height: 190,
),
Text('Test1'),
Text('Test2'),
Text('Test3'),
ListView.builder(
itemBuilder: (context, index) {
return ListTile(
onTap: () {},
title: Text('#'),
);
},
)
// StreamBuilder(
// stream: _clientsService.allClients(),
// builder: (context, snapshot) {
// switch (snapshot.connectionState) {
// case ConnectionState.waiting:
// case ConnectionState.active: //implicit fall through
// if (snapshot.hasData) {
// final allClients = snapshot.data as Iterable<Client>;
// return ClientsListView(
// clients: allClients,
// onTap: (clients) {},
// );
// } else {
// return const CircularProgressIndicator();
// }
// default:
// return const CircularProgressIndicator();
// }
// },
// ),
],
),
);
}
}
Before adding List.viewbuilder
After adding list.viewbuilder
for the first picture (before adding Listview.builder) items are rendered in center because you have a Row inside your Column, Column & Row have a default CrossAxisAlignment.center
After adding the ListView.builder, the log will be showing you an error, ListView here needs to be either inside an Expanded or shrinkWrap: true,
Setting an Expanded as a parent for the ListView will make the listview scrollable only, but adding the attribute shrinkWrap: true will stop the scrolling feature in your Listview, and then you will have to put your Column inside a Listview or SingleChildScrollView

How to create a custom gridview with appropriate aspect ratio?

I am trying to create a custom image picker that looks something like this:
As you can see the images are capped at a set height however maintain their aspect ratio (i.e. vertical images are vertical and horizontal images are horizontal). I have created the entire custom image picker. However, I'm struggling with the aspect ratio part. I'd prefer not to use a library, however, if it's easier then please provide the adjusted code.
Could you please provide a solution with code?
FYI I'm using photo_manager to retrieve the images/videos.
This is what it all looks like right now:
Here is my code:
class MediaGrid extends StatefulWidget {
#override
_MediaGridState createState() => _MediaGridState();
}
class _MediaGridState extends State<MediaGrid> {
List<Widget> _mediaList = [];
int currentPage = 0;
int? lastPage;
#override
void initState() {
super.initState();
_fetchNewMedia();
}
_handleScrollEvent(ScrollNotification scroll) {
if (scroll.metrics.pixels / scroll.metrics.maxScrollExtent > 0.33) {
if (currentPage != lastPage) {
_fetchNewMedia();
}
}
}
_fetchNewMedia() async {
lastPage = currentPage;
var result = await PhotoManager.requestPermission();
if (result) {
// success
//load the album list
List<AssetPathEntity> albums =
await PhotoManager.getAssetPathList(onlyAll: true);
print(albums);
List<AssetEntity> media =
await albums[0].getAssetListPaged(currentPage, 60);
print(media);
List<Widget> temp = [];
for (var asset in media) {
temp.add(
FutureBuilder<dynamic>(
future: asset.thumbDataWithSize(300, 300),
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done)
return Stack(
children: <Widget>[
Expanded(
child: Image.memory(snapshot.data, fit: BoxFit.cover),
),
if (asset.type == AssetType.video)
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: EdgeInsets.only(right: 5, bottom: 5),
child: Icon(
Icons.videocam_rounded,
color: Colors.white,
),
),
),
],
);
return Container();
},
),
);
}
setState(() {
_mediaList.addAll(temp);
currentPage++;
});
} else {
// fail
/// if result is fail, you can call `PhotoManager.openSetting();` to open android/ios applicaton's setting to get permission
}
}
#override
Widget build(BuildContext context) {
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification scroll) {
return _handleScrollEvent(scroll);
},
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: _mediaList.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 5.0,
crossAxisSpacing: 5.0,
),
itemBuilder: (BuildContext context, int index) {
return _mediaList[index];
}),
);
}
}
This idea will only work if you wish to give each image a single specified height. And using fit: BoxFit.cover to fill up the remaining space.
Now you must find a way to get the width of each image, in my code its of Network Images
From here use the width as the flex value.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
Future<Size> _calculateImageDimension(String url) {
Completer<Size> completer = Completer();
Image image = Image.network(url);
image.image.resolve(ImageConfiguration()).addListener(
ImageStreamListener(
(ImageInfo image, bool synchronousCall) {
var myImage = image.image;
Size size = Size(myImage.width.toDouble(), myImage.height.toDouble());
completer.complete(size);
},
),
);
return completer.future;
}
#override
Widget build(BuildContext context) {
//for odd no. of images you might have to add more conditions to your widget
final _netWorkimages = [
'https://images.pexels.com/photos/7179053/pexels-photo-7179053.jpeg?cs=srgb&dl=pexels-olya-prutskova-7179053.jpg&fm=jpg',
'https://images.pexels.com/photos/7527509/pexels-photo-7527509.jpeg?cs=srgb&dl=pexels-john-lee-7527509.jpg&fm=jpg',
'https://images.pexels.com/photos/8018591/pexels-photo-8018591.jpeg?cs=srgb&dl=pexels-inna-stellinna-8018591.jpg&fm=jpg',
'https://images.pexels.com/photos/3244513/pexels-photo-3244513.jpeg?cs=srgb&dl=pexels-andy-vu-3244513.jpg&fm=jpg',
'https://images.pexels.com/photos/694587/pexels-photo-694587.jpeg?cs=srgb&dl=pexels-samuel-silitonga-694587.jpg&fm=jpg',
'https://images.pexels.com/photos/5121986/pexels-photo-5121986.jpeg?cs=srgb&dl=pexels-marcelo-chagas-5121986.jpg&fm=jpg',
'https://images.pexels.com/photos/4519234/pexels-photo-4519234.jpeg?cs=srgb&dl=pexels-dinielle-de-veyra-4519234.jpg&fm=jpg',
'https://images.pexels.com/photos/2286385/pexels-photo-2286385.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
'https://images.pexels.com/photos/35629/bing-cherries-ripe-red-fruit.jpg?cs=srgb&dl=pexels-pixabay-35629.jpg&fm=jpg',
'https://images.pexels.com/photos/4033324/pexels-photo-4033324.jpeg?cs=srgb&dl=pexels-karolina-grabowska-4033324.jpg&fm=jpg'
];
List<Future<Size>> _niSizes = [];
_netWorkimages.forEach((url) {
_niSizes.add(_calculateImageDimension(url));
});
return FutureBuilder<List<Size>>(
future: Future.wait(_niSizes),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: CircularProgressIndicator(),
);
else
return ListView.builder(
itemCount: _netWorkimages.length - 1,
itemBuilder: (context, i) {
return i.isEven
? Container(
height: 120,
child: Row(
children: [
Flexible(
flex: snapshot.data![i].width.toInt(),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Image(
image: NetworkImage(_netWorkimages[i]),
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
),
)),
Flexible(
flex: snapshot.data![i + 1].width.toInt(),
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Image(
image: NetworkImage(_netWorkimages[i + 1]),
fit: BoxFit.cover,
height: double.infinity,
width: double.infinity,
),
)),
],
),
)
: SizedBox.shrink();
});
},
);
}
}
I hope this is thing you are looking for, replace container with image.
import 'package:flutter/material.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'dart:math' as math;
class TestScreen extends StatefulWidget {
TestScreen({Key? key}) : super(key: key);
#override
_TestScreenState createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
final _items = List.generate(
100,
(index) => ClipRRect(
borderRadius: BorderRadius.circular(
8,
),
child: Container(
height: 124,
color: Color(
(math.Random().nextDouble() * 0xFFFFFF).toInt(),
).withOpacity(1.0),
),
));
#override
Widget build(BuildContext context) {
return Container(
child: StaggeredGridView.countBuilder(
mainAxisSpacing: 2,
crossAxisSpacing: 2,
crossAxisCount: 6,
itemCount: 100,
itemBuilder: (context, index) {
return _items[index];
},
staggeredTileBuilder: (index) {
if (index % 6 == 0 || index % 6 == 3) {
return StaggeredTile.count(2, 1);
} else if (index % 6 == 1 || index % 6 == 2) {
return StaggeredTile.count(4, 1);
} else
return StaggeredTile.count(3, 1);
},
),
);
}
}
You can use https://pub.dev/packages/flutter_staggered_grid_view
This plugin has options to modify the aspect ratio

Flutter. GridView inside Container

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'Login.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
image:DecorationImage(
image: AssetImage("images/black_background_logo.png"),
fit: BoxFit.cover,
)
),
child: Column(
children: [
CarouselDemo(),
HomePanel()
],
),
);
}
}
List<String> images = [
'https://skalka-app.ru/banners/1.png',
'https://skalka-app.ru/banners/2.png',
'https://skalka-app.ru/banners/3.png',
] ;
class CarouselDemo extends StatelessWidget {
CarouselController buttonCarouselController = CarouselController();
#override
Widget build(BuildContext context) => CarouselSlider(
options: CarouselOptions(
height: MediaQuery.of(context).size.height*0.7,
viewportFraction: 1.0,
enableInfiniteScroll: true,
reverse: false,
autoPlay: true,
autoPlayInterval: Duration(seconds: 8),
autoPlayAnimationDuration: Duration(milliseconds: 800),
autoPlayCurve: Curves.fastOutSlowIn,
),
items: images.map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
//width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height*0.7,
decoration: BoxDecoration(
color: Colors.amber
),
child: Image.network(i,fit: BoxFit.cover, height: MediaQuery.of(context).size.height*0.7,)
);
},
);
}).toList(),
);
}
class HomePanel extends StatelessWidget {
#override
Widget build(BuildContext context) {
final double height = MediaQuery.of(context).size.height;
List<String> data = <String>["Twitter", "Reddit", "YouTube", "Facebook",
"Vimeo", "GitHub", "GitLab", "BitBucket", "LinkedIn", "Medium",
"Tumblr", "Instagram", "Pinterest"];
List<RaisedButton> myWidgets = data.map((item) {
return new RaisedButton(
child: new Text(item),
onPressed: () async {
}
);
}).toList();
GridView myGrid = GridView.count(
crossAxisCount: 3,
children: myWidgets
);
return Container(
height: height*0.3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
child: myGrid
);
}
}
I'm trying to add a GridView to a Container, but an indent appears at the top. Please tell me how to fix this?
I painted the Container red to show that there is a padding on top. I could not find a solution to this problem on the Internet. I'm new to Flutter, maybe I missed an important point in building this widget.
You can try wrap GridView with a MediaQuery.removePadding() then set removeTop property to True.
MediaQuery.removePadding(
context: context,
removeTop: true,
child: GridView(
.......
)
);
I have used your code pretty much, just for the Carousel, I have used the ListView.builder(). Rest is fine.
The catch is to use Expanded class inside your Column() to take the height automatically for the Carousel
Follow the code along, and see the result as well, no extra space in the UI in the GridView
class _MyHomePageState extends State<MyHomePage> {
List<String> images = [
'https://skalka-app.ru/banners/1.png',
'https://skalka-app.ru/banners/2.png',
'https://skalka-app.ru/banners/3.png',
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: double.infinity,
child: Column(
children: [
// Expanded used to take up the space
Expanded(
// ListView.builder, use your carousel here
child: ListView.builder(
shrinkWrap: true,
itemCount: images.length,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index){
// look at this as well, no height, only width
// given for the image
return Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(images[index])
)
)
);
}
)
),
HomePanel()
],
),
)
);
}
}
class HomePanel extends StatelessWidget {
#override
Widget build(BuildContext context) {
final double height = MediaQuery.of(context).size.height;
List<String> data = <String>["Twitter", "Reddit", "YouTube", "Facebook",
"Vimeo", "GitHub", "GitLab", "BitBucket", "LinkedIn", "Medium",
"Tumblr", "Instagram", "Pinterest"];
List<RaisedButton> myWidgets = data.map((item) {
return new RaisedButton(
child: new Text(item),
onPressed: () async {
}
);
}).toList();
GridView myGrid = GridView.count(
crossAxisCount: 3,
children: myWidgets
);
return Container(
height: height*0.3,
width: MediaQuery.of(context).size.width,
color: Colors.red,
child: myGrid
);
}
}
Result
Look at the design closely in the result, no extra spacing or padding

How to give some space (margin/padding) between pages in PageView?

I am using PageView.builder to create pages.
PageView.builder(
itemCount: _pagesList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
color: _pagesList[index],
);
}
)
What I currently have:
What I want:
i.e. I want to provide some Padding between pages (when they are being scrolled)
Reason: I will display Images in these pages, and since the Images will cover the full width of each page, it doesn't look nice when we scroll pages, since they are knitted together, like this:
How can I solve this?
PageController imagesController =
PageController(initialPage: 0, viewportFraction: 1.1);
PageView(
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.only(left: 10, right: 10),
child: Container(
color: _pagesList[index],
),
);
}
),
If you want to add padding and still have your pages as wide as the screen:
I needed this exact same thing, also for displaying images. I wanted to add padding but at the same time have each image take up the entire screen width. I figured I could use Fahad Javed's technique and tweaking it a little bit by calculating the viewPortFraction based on the screen width and padding.
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width; // screen width
double screenPad = 16.0; // screen padding for swiping between pages
int _currentPosition = 0;
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: data.length,
controller: PageController(
initialPage: _currentPosition,
viewportFraction:
1 + (screenPad * 2 / screenWidth)), // calculate viewPortFraction
onPageChanged: (int value) {
_currentPosition = value;
},
itemBuilder: (BuildContext context, int position) {
return Padding(
padding: EdgeInsets.only(left: screenPad, right: screenPad),
child: Text('YOUR PAGE CONTENT'),
);
},
);
}
This answer from on the question asked by Amon Kataria Github
final pageController = PageController(viewportFraction: 1.1);
PageView.builder(
controller: pageController,
itemCount: _pagesList.length,
itemBuilder: (BuildContext context, int index) {
return FractionallySizedBox(
widthFactor: 1 / pageController.viewportFraction,
child: Container(
color: _pagesList[index],
),
);
},
);
Thanks #mono0926
Best effort:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: MyPageView()
)
);
}
}
class MyPageView extends StatefulWidget {
MyPageView({Key key}) : super(key: key);
_MyPageViewState createState() => _MyPageViewState();
}
class _MyPageViewState extends State<MyPageView> {
#override
Widget build(BuildContext context) {
return PageView(
children: <Widget>[
Container(
color: Colors.black,
child: Card(
color: Colors.red,
)
),
Container(
color: Colors.black,
child: Card(
color: Colors.blue,
),
),
Container(
color: Colors.black,
child: Card(
color: Colors.green,
),
),
],
);
}
}
You just need to add some padding around each page and the width of the page view must be at least the 'card width + the padding from both sides'. This worked for me:
class MyWidget extends StatelessWidget {
final _CARD_WIDTH = 220.0;
final PageController _controller = PageController(initialPage: 0);
#override
Widget build(BuildContext context) {
return Container(
height: _CARD_WIDTH,
width: _CARD_WIDTH + 32,
child: PageView(
scrollDirection: Axis.horizontal,
controller: _controller,
children: <Widget>[
_buildImageCard("1"),
_buildImageCard("2"),
_buildImageCard("3"),
],
),
);
}
Widget _buildImageCard(String text) {
return Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16),
child: Container(
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(15),
),
width: _CARD_WIDTH,
height: _CARD_WIDTH,
child: Center(
child: Text(text),
),
),
);
}
}

Flutter :how can add other widget under gridview after a certain number of index

I am working with flutter gridview project in where i want show another widget after certain number of index.
how can i add widget after each 6 index of gridview
GridView.builder(shrinkWrap: true,gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2,childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.width*0.9),),
physics: NeverScrollableScrollPhysics(),
itemCount: widget.dicovervehiclelist.length,
itemBuilder: (BuildContext context, int index) {
return vehicleview(
widget.dicovervehiclelist[index], context,widget.dicovervehiclelist.length,index);
}),
We can put business logic inside itemBuilder.
If the index+1 can be divided by 6, then we put another widget. In this case, I put Text("This is Separator") widget.
Widget renderSeparator(){
return Text("This is Separator");
}
Widget renderGrids() {
Widget grids = GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.width * 0.9),
),
// physics: NeverScrollableScrollPhysics(),
// itemCount: widget.dicovervehiclelist.length,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
// return vehicleview(
// widget.dicovervehiclelist[index],
// context,widget.dicovervehiclelist.length,
// index);
return Container(
child: Column(
children: <Widget>[
Text("Main Content"),
if ((index+1) % 6 == 0)
renderSeparator()
],
)
);
},
);
return grids;
}
- updated requirement by Hitanshu
thanks ...but its only below in that index which is ==5 and so on , i want show below the both index like 4 and 5 ..where crossAxisCount:1
If we want to implement combination of Grid and List View, we need to have
CustomScrollView
SliverGrid
SliverList
SliverChildListDelegate
Working Example App
You may look into repository. Github
And this is the full Code
import 'package:flutter/material.dart';
class GridViewListViewIndex extends StatelessWidget {
final int newsFeedCount = 18;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Special after 6th'),
),
body: Container(
child: renderScrollArea(context),
),
);
}
List<Widget> businessLogic(BuildContext context) {
List<Widget> temp = [];
for (var i = 1; i < newsFeedCount+1; i++) {
if (i % 6 == 1) {
temp.add(renderGrids(context));
}
if (i % 6 == 0) {
temp.add(renderLists(context));
}
}
return temp;
}
Widget renderScrollArea(BuildContext context) {
final scrollableArea = CustomScrollView(
slivers: businessLogic(context),
// Below lines are neglected as we have more complex requirement
// slivers: <Widget>[
// renderGrids(context),
// renderLists(context),
// renderGrids(context),
// renderLists(context),
// ],
);
return scrollableArea;
}
Widget renderLists(BuildContext context) {
final lists = SliverList(
delegate: SliverChildListDelegate(
[
NewsFeed(),
],
),
);
return lists;
}
Widget renderGrids(BuildContext context) {
final grids = SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
delegate: SliverChildListDelegate(
[
NewsFeed(),
NewsFeed(),
NewsFeed(),
NewsFeed(),
NewsFeed(),
NewsFeed(),
],
),
);
return grids;
}
}
class NewsFeed extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white30,
border: Border.all(
color: Colors.black26,
width: 1.0,
),
),
padding: EdgeInsets.all(16.0),
child: Center(
child: Text("Content"),
),
);
}
}
Demo