如何在 Flutter 中创建 GridView 布局
How to create GridView Layout in Flutter
我正在尝试在 flutter 中布置一个 4x4 的瓷砖网格。我设法用列和行来做到这一点。但是现在我找到了 GridView
组件。谁能举例说明如何使用它?
我无法真正理解文档。我似乎没有得到我想要的结果。
GridView
is used for implementing material grid lists。如果您知道您有固定数量的项目并且数量不是很多(16 个就可以),您可以使用 GridView.count
。但是,您应该注意 GridView
是可滚动的,如果这不是您想要的,您最好只使用行和列。
import 'dart:collection';
import 'package:flutter/scheduler.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.orange,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget{
@override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text('Grid Demo'),
),
body: new GridView.count(
crossAxisCount: 4,
children: new List<Widget>.generate(16, (index) {
return new GridTile(
child: new Card(
color: Colors.blue.shade200,
child: new Center(
child: new Text('tile $index'),
)
),
);
}),
),
);
}
}
将图像加载到图块中的简单示例。
import 'package:flutter/material.dart';
void main() {
runApp( MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white30,
child: GridView.count(
crossAxisCount: 4,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: <String>[
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
].map((String url) {
return GridTile(
child: Image.network(url, fit: BoxFit.cover));
}).toList()),
);
}
}
Flutter Gallery 应用程序包含一个真实示例,可以在 here.
中找到
请访问此repo。
Widget _gridView() {
return GridView.count(
crossAxisCount: 4,
padding: EdgeInsets.all(4.0),
childAspectRatio: 8.0 / 9.0,
children: itemList
.map(
(Item) => ItemList(item: Item),
)
.toList(),
);
}
下面的截图包含 crossAxisCount: 2
GridView
针对不同场景的命名构造函数很少,
构造函数
GridView
GridView.builder
GridView.count
GridView.custom
GridView.extent
下面是GridView
构造函数的例子:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
List<String> images = [
"https://uae.microless.com/cdn/no_image.jpg",
"https://images-na.ssl-images-amazon.com/images/I/81aF3Ob-2KL._UX679_.jpg",
"https://www.boostmobile.com/content/dam/boostmobile/en/products/phones/apple/iphone-7/silver/device-front.png.transform/pdpCarousel/image.jpg",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgUgs8_kmuhScsx-J01d8fA1mhlCR5-1jyvMYxqCB8h3LCqcgl9Q",
"https://ae01.alicdn.com/kf/HTB11tA5aiAKL1JjSZFoq6ygCFXaw/Unlocked-Samsung-GALAXY-S2-I9100-Mobile-Phone-Android-Wi-Fi-GPS-8-0MP-camera-Core-4.jpg_640x640.jpg",
"https://media.ed.edmunds-media.com/gmc/sierra-3500hd/2018/td/2018_gmc_sierra-3500hd_f34_td_411183_1600.jpg",
"https://hips.hearstapps.com/amv-prod-cad-assets.s3.amazonaws.com/images/16q1/665019/2016-chevrolet-silverado-2500hd-high-country-diesel-test-review-car-and-driver-photo-665520-s-original.jpg",
"https://www.galeanasvandykedodge.net/assets/stock/ColorMatched_01/White/640/cc_2018DOV170002_01_640/cc_2018DOV170002_01_640_PSC.jpg",
"https://media.onthemarket.com/properties/6191869/797156548/composite.jpg",
"https://media.onthemarket.com/properties/6191840/797152761/composite.jpg",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView(
physics: BouncingScrollPhysics(), // if you want IOS bouncing effect, otherwise remove this line
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),//change the number as you want
children: images.map((url) {
return Card(child: Image.network(url));
}).toList(),
),
);
}
}
如果您希望您的 GridView 项目根据内容动态变化,您可以用几行代码来做到这一点,但最简单的方法是使用 StaggeredGridView
包。我已经用示例 .
提供了答案
下面是一个 GridView.count
:
的例子
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 4,
children: List.generate(40, (index) {
return Card(
child: Image.network("https://robohash.org/$index"),
); //robohash.org api provide you different images for any number you are giving
}),
),
);
}
}
以上代码段的屏幕截图:
SliverGridView
的示例:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: SliverGrid.count(
crossAxisSpacing: 10.0,
crossAxisCount: 2,
children: List.generate(20, (index) {
return Card(child: Image.network("https://robohash.org/$index"));
}),
),
),
],
)
);
}
}
根据您的需要使用任何一个。
GridView.count(...)
GridView.count(
crossAxisCount: 2,
children: <Widget>[
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
],
)
GridView.builder(...)
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (_, index) => FlutterLogo(),
itemCount: 4,
)
GridView(...)
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
children: <Widget>[
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
],
)
GridView.custom(...)
GridView.custom(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
childrenDelegate: SliverChildListDelegate(
[
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
],
),
)
GridView.extent(...)
GridView.extent(
maxCrossAxisExtent: 400,
children: <Widget>[
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
FlutterLogo(),
],
)
输出(全部相同):
您可以使用 flutter_layout_grid 包
首先,我们需要将其添加到our pubspec.yaml
:
dependencies:
flutter_layout_grid: ^1.0.3
然后,我们可以定义一个自定义 ItemCardLayoutGrid
小部件来显示 LayoutGrid
小部件中的每个 ItemCard
:
import 'package:flutter_layout_grid/flutter_layout_grid.dart';
class ItemCardLayoutGrid extends StatelessWidget {
const ItemCardLayoutGrid({
Key? key,
required this.crossAxisCount,
required this.items,
})
// we only plan to use this with 1 or 2 columns
: assert(crossAxisCount == 1 || crossAxisCount == 2),
// assume we pass an list of 4 items for simplicity
assert(items.length == 4),
super(key: key);
final int crossAxisCount;
final List<ItemCardData> items;
@override
Widget build(BuildContext context) {
return LayoutGrid(
// set some flexible track sizes based on the crossAxisCount
columnSizes: crossAxisCount == 2 ? [1.fr, 1.fr] : [1.fr],
// set all the row sizes to auto (self-sizing height)
rowSizes: crossAxisCount == 2
? const [auto, auto]
: const [auto, auto, auto, auto],
rowGap: 40, // equivalent to mainAxisSpacing
columnGap: 24, // equivalent to crossAxisSpacing
// note: there's no childAspectRatio
children: [
// render all the cards with *automatic child placement*
for (var i = 0; i < items.length; i++)
ItemCard(data: items[i]),
],
);
}
}
并在循环中传递子项列表(我们的 ItemCard
小部件):
children: [
// render all the cards with *automatic child placement*
for (var i = 0; i < items.length; i++)
ItemCard(data: items[i]),
]
我正在尝试在 flutter 中布置一个 4x4 的瓷砖网格。我设法用列和行来做到这一点。但是现在我找到了 GridView
组件。谁能举例说明如何使用它?
我无法真正理解文档。我似乎没有得到我想要的结果。
GridView
is used for implementing material grid lists。如果您知道您有固定数量的项目并且数量不是很多(16 个就可以),您可以使用 GridView.count
。但是,您应该注意 GridView
是可滚动的,如果这不是您想要的,您最好只使用行和列。
import 'dart:collection';
import 'package:flutter/scheduler.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.orange,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget{
@override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text('Grid Demo'),
),
body: new GridView.count(
crossAxisCount: 4,
children: new List<Widget>.generate(16, (index) {
return new GridTile(
child: new Card(
color: Colors.blue.shade200,
child: new Center(
child: new Text('tile $index'),
)
),
);
}),
),
);
}
}
将图像加载到图块中的简单示例。
import 'package:flutter/material.dart';
void main() {
runApp( MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white30,
child: GridView.count(
crossAxisCount: 4,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: <String>[
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
'http://www.for-example.org/img/main/forexamplelogo.png',
].map((String url) {
return GridTile(
child: Image.network(url, fit: BoxFit.cover));
}).toList()),
);
}
}
Flutter Gallery 应用程序包含一个真实示例,可以在 here.
中找到请访问此repo。
Widget _gridView() {
return GridView.count(
crossAxisCount: 4,
padding: EdgeInsets.all(4.0),
childAspectRatio: 8.0 / 9.0,
children: itemList
.map(
(Item) => ItemList(item: Item),
)
.toList(),
);
}
下面的截图包含 crossAxisCount: 2
GridView
针对不同场景的命名构造函数很少,
构造函数
GridView
GridView.builder
GridView.count
GridView.custom
GridView.extent
下面是GridView
构造函数的例子:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
List<String> images = [
"https://uae.microless.com/cdn/no_image.jpg",
"https://images-na.ssl-images-amazon.com/images/I/81aF3Ob-2KL._UX679_.jpg",
"https://www.boostmobile.com/content/dam/boostmobile/en/products/phones/apple/iphone-7/silver/device-front.png.transform/pdpCarousel/image.jpg",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgUgs8_kmuhScsx-J01d8fA1mhlCR5-1jyvMYxqCB8h3LCqcgl9Q",
"https://ae01.alicdn.com/kf/HTB11tA5aiAKL1JjSZFoq6ygCFXaw/Unlocked-Samsung-GALAXY-S2-I9100-Mobile-Phone-Android-Wi-Fi-GPS-8-0MP-camera-Core-4.jpg_640x640.jpg",
"https://media.ed.edmunds-media.com/gmc/sierra-3500hd/2018/td/2018_gmc_sierra-3500hd_f34_td_411183_1600.jpg",
"https://hips.hearstapps.com/amv-prod-cad-assets.s3.amazonaws.com/images/16q1/665019/2016-chevrolet-silverado-2500hd-high-country-diesel-test-review-car-and-driver-photo-665520-s-original.jpg",
"https://www.galeanasvandykedodge.net/assets/stock/ColorMatched_01/White/640/cc_2018DOV170002_01_640/cc_2018DOV170002_01_640_PSC.jpg",
"https://media.onthemarket.com/properties/6191869/797156548/composite.jpg",
"https://media.onthemarket.com/properties/6191840/797152761/composite.jpg",
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView(
physics: BouncingScrollPhysics(), // if you want IOS bouncing effect, otherwise remove this line
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),//change the number as you want
children: images.map((url) {
return Card(child: Image.network(url));
}).toList(),
),
);
}
}
如果您希望您的 GridView 项目根据内容动态变化,您可以用几行代码来做到这一点,但最简单的方法是使用 StaggeredGridView
包。我已经用示例
下面是一个 GridView.count
:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView.count(
crossAxisCount: 4,
children: List.generate(40, (index) {
return Card(
child: Image.network("https://robohash.org/$index"),
); //robohash.org api provide you different images for any number you are giving
}),
),
);
}
}
以上代码段的屏幕截图:
SliverGridView
的示例:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: ExampleGrid(),
),
);
class ExampleGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
primary: false,
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(20.0),
sliver: SliverGrid.count(
crossAxisSpacing: 10.0,
crossAxisCount: 2,
children: List.generate(20, (index) {
return Card(child: Image.network("https://robohash.org/$index"));
}),
),
),
],
)
);
}
}
根据您的需要使用任何一个。
GridView.count(...)
GridView.count( crossAxisCount: 2, children: <Widget>[ FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), ], )
GridView.builder(...)
GridView.builder( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), itemBuilder: (_, index) => FlutterLogo(), itemCount: 4, )
GridView(...)
GridView( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), children: <Widget>[ FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), ], )
GridView.custom(...)
GridView.custom( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), childrenDelegate: SliverChildListDelegate( [ FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), ], ), )
GridView.extent(...)
GridView.extent( maxCrossAxisExtent: 400, children: <Widget>[ FlutterLogo(), FlutterLogo(), FlutterLogo(), FlutterLogo(), ], )
输出(全部相同):
您可以使用 flutter_layout_grid 包
首先,我们需要将其添加到our pubspec.yaml
:
dependencies:
flutter_layout_grid: ^1.0.3
然后,我们可以定义一个自定义 ItemCardLayoutGrid
小部件来显示 LayoutGrid
小部件中的每个 ItemCard
:
import 'package:flutter_layout_grid/flutter_layout_grid.dart';
class ItemCardLayoutGrid extends StatelessWidget {
const ItemCardLayoutGrid({
Key? key,
required this.crossAxisCount,
required this.items,
})
// we only plan to use this with 1 or 2 columns
: assert(crossAxisCount == 1 || crossAxisCount == 2),
// assume we pass an list of 4 items for simplicity
assert(items.length == 4),
super(key: key);
final int crossAxisCount;
final List<ItemCardData> items;
@override
Widget build(BuildContext context) {
return LayoutGrid(
// set some flexible track sizes based on the crossAxisCount
columnSizes: crossAxisCount == 2 ? [1.fr, 1.fr] : [1.fr],
// set all the row sizes to auto (self-sizing height)
rowSizes: crossAxisCount == 2
? const [auto, auto]
: const [auto, auto, auto, auto],
rowGap: 40, // equivalent to mainAxisSpacing
columnGap: 24, // equivalent to crossAxisSpacing
// note: there's no childAspectRatio
children: [
// render all the cards with *automatic child placement*
for (var i = 0; i < items.length; i++)
ItemCard(data: items[i]),
],
);
}
}
并在循环中传递子项列表(我们的 ItemCard
小部件):
children: [
// render all the cards with *automatic child placement*
for (var i = 0; i < items.length; i++)
ItemCard(data: items[i]),
]