如何在 StaggeredGridView 中将图块居中
How to center a tile within a StaggeredGridView
我正在 Flutter 中使用 StaggeredGridView,如果某个图块将成为该“行”中的唯一图块,我似乎看不到一种方法可以使图块居中。
例如,如果我将 StaggeredGridView 的 crossAxisCount 设置为 6;然后将图块的 crossAxisCellCount 发送到 4,图块从左侧开始占据 4 个“单元格”,如果没有可以占据 2 个单元格的图块,则在右侧留下 2 个“单元格”的空值 space。
是否可以强制磁贴居中?本质上,让它占据第2-5个单元格,左边留1个空单元格,右边留1个空单元格?
我试过将 StaggeredGridView 包装在中心小部件中,但这似乎没有什么不同。
目前我有一个有状态的小部件,它具有以下构建方法。
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
);
}
在该小部件的视图模型中,StaggeredGridView 使用了两个相关函数:创建 StaggeredTiles 的 displayCardTiles 函数,以及创建进入图块的小部件的 displayCards 函数。这两个函数如下:
List<StaggeredTile> _buildDisplayCardTiles(){
List<StaggeredTile> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(StaggeredTile.fit(bioCategory.crossAxisCellCount));
}
return myList;
}
List<Widget> _buildDisplayCards(){
List<Widget> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(ProfileItemCard(bioCategory: bioCategory));
}
return myList;
}
“ProfileItemCard”只是一个显示各种文本小部件和复选框的卡片小部件,但它的内容不会影响卡片在 StaggeredGridView 中的位置。
我也试过将 ProfileItemCard 包装在中心小部件中,但这对卡片的显示方式没有任何影响。
尝试在中心包裹,然后在容器中对齐 属性
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: Container(
margin: EdgeInsets.all(50),
height: double.infinity,
alignment: Alignment.center,
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
),
);
}
简介: 我自己也遇到过这个问题,谢谢你的提问
Baseline:计算模型计数和横轴计数的余数(原题中的userProfile.bioCategories
和6
),然后将一行中的“剩余”图块(均匀分布)并跨越整个网格宽度。
演示
复制: Github.
代码(单文件解决方案,唯一的先决条件是flutter_staggered_grid_view: 0.4.0
):
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
void main() {
runApp(const TabBarDemo());
}
generateRandomColor() => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
class Model {
final num;
Model({this.num});
}
class ModelWidget extends StatelessWidget {
final Model model;
ModelWidget(this.model) : super();
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Container(
color: generateRandomColor(),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
model.num.toString(),
textAlign: TextAlign.center,
),
],
)),
);
}
}
class TabBarDemo extends StatelessWidget {
const TabBarDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// ------------------------------- given ----------------------------------
const CROSS_AXIS_COUNT = 6;
const CROSS_AXIS_SPACING = 10.0;
const MAIN_AXIS_SPACING = 10.0;
final models = List.generate(20, (_) => Model(num: Random().nextInt(100)));
// ------------------------------------------------------------------------
// ------------------------------ solution --------------------------------
final modelCount = models.length;
final int fittingCount = modelCount - modelCount % CROSS_AXIS_COUNT;
// ------------------------------------------------------------------------
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(
child: Text("problem"),
),
Tab(
child: Text("solution (static)"),
),
Tab(icon: Text("solution (builder)")),
],
),
title: const Text('staggered_grid - centering tiles'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: TabBarView(
children: [
// ------------------------------ problem ---------------------------------
Scaffold(
body: StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: models.map((m) => StaggeredTile.fit(1)).toList(),
children: models.map((m) => ModelWidget(m)).toList(),
),
),
// ------------------------------------------------------------------------
// ------------------------- solution (static) ----------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: [
...models.sublist(0, fittingCount).map((m) => StaggeredTile.fit(1)).toList(),
if (modelCount != fittingCount) StaggeredTile.fit(CROSS_AXIS_COUNT)
],
children: [
...models.sublist(0, fittingCount).map((m) => ModelWidget(m)).toList(),
if (modelCount != fittingCount)
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList())
],
);
}),
),
// ------------------------------------------------------------------------
// ------------------------- solution (builder) ---------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.countBuilder(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
itemCount: modelCount == fittingCount ? fittingCount : fittingCount + 1,
itemBuilder: (context, index) {
if (index < fittingCount) {
return ModelWidget(models.elementAt(index));
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList());
}
},
staggeredTileBuilder: (int index) {
if (index < fittingCount) {
return StaggeredTile.count(1, 1);
} else {
return StaggeredTile.count(CROSS_AXIS_COUNT, 1);
}
});
}),
),
// ------------------------------------------------------------------------
],
),
),
),
),
);
}
}
我正在 Flutter 中使用 StaggeredGridView,如果某个图块将成为该“行”中的唯一图块,我似乎看不到一种方法可以使图块居中。
例如,如果我将 StaggeredGridView 的 crossAxisCount 设置为 6;然后将图块的 crossAxisCellCount 发送到 4,图块从左侧开始占据 4 个“单元格”,如果没有可以占据 2 个单元格的图块,则在右侧留下 2 个“单元格”的空值 space。
是否可以强制磁贴居中?本质上,让它占据第2-5个单元格,左边留1个空单元格,右边留1个空单元格?
我试过将 StaggeredGridView 包装在中心小部件中,但这似乎没有什么不同。
目前我有一个有状态的小部件,它具有以下构建方法。
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
);
}
在该小部件的视图模型中,StaggeredGridView 使用了两个相关函数:创建 StaggeredTiles 的 displayCardTiles 函数,以及创建进入图块的小部件的 displayCards 函数。这两个函数如下:
List<StaggeredTile> _buildDisplayCardTiles(){
List<StaggeredTile> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(StaggeredTile.fit(bioCategory.crossAxisCellCount));
}
return myList;
}
List<Widget> _buildDisplayCards(){
List<Widget> myList = [];
for(var bioCategory in userProfile.bioCategories!){
myList.add(ProfileItemCard(bioCategory: bioCategory));
}
return myList;
}
“ProfileItemCard”只是一个显示各种文本小部件和复选框的卡片小部件,但它的内容不会影响卡片在 StaggeredGridView 中的位置。
我也试过将 ProfileItemCard 包装在中心小部件中,但这对卡片的显示方式没有任何影响。
尝试在中心包裹,然后在容器中对齐 属性
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ProfileEditScreenViewModel>(
create: (context) => model,
child: Consumer<ProfileEditScreenViewModel>(
builder: (context, model, child) => Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(model.screenTitle),
),
body: Center(
child: Container(
margin: EdgeInsets.all(50),
height: double.infinity,
alignment: Alignment.center,
child: StaggeredGridView.count(
crossAxisCount: 6,
shrinkWrap: true,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
staggeredTiles: model.displayCardTiles,
children: model.displayCards,
),
),
),
),
),
);
}
简介: 我自己也遇到过这个问题,谢谢你的提问
Baseline:计算模型计数和横轴计数的余数(原题中的userProfile.bioCategories
和6
),然后将一行中的“剩余”图块(均匀分布)并跨越整个网格宽度。
演示
复制: Github.
代码(单文件解决方案,唯一的先决条件是flutter_staggered_grid_view: 0.4.0
):
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
void main() {
runApp(const TabBarDemo());
}
generateRandomColor() => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
class Model {
final num;
Model({this.num});
}
class ModelWidget extends StatelessWidget {
final Model model;
ModelWidget(this.model) : super();
@override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Container(
color: generateRandomColor(),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
model.num.toString(),
textAlign: TextAlign.center,
),
],
)),
);
}
}
class TabBarDemo extends StatelessWidget {
const TabBarDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// ------------------------------- given ----------------------------------
const CROSS_AXIS_COUNT = 6;
const CROSS_AXIS_SPACING = 10.0;
const MAIN_AXIS_SPACING = 10.0;
final models = List.generate(20, (_) => Model(num: Random().nextInt(100)));
// ------------------------------------------------------------------------
// ------------------------------ solution --------------------------------
final modelCount = models.length;
final int fittingCount = modelCount - modelCount % CROSS_AXIS_COUNT;
// ------------------------------------------------------------------------
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: const TabBar(
tabs: [
Tab(
child: Text("problem"),
),
Tab(
child: Text("solution (static)"),
),
Tab(icon: Text("solution (builder)")),
],
),
title: const Text('staggered_grid - centering tiles'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: TabBarView(
children: [
// ------------------------------ problem ---------------------------------
Scaffold(
body: StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: models.map((m) => StaggeredTile.fit(1)).toList(),
children: models.map((m) => ModelWidget(m)).toList(),
),
),
// ------------------------------------------------------------------------
// ------------------------- solution (static) ----------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.count(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
staggeredTiles: [
...models.sublist(0, fittingCount).map((m) => StaggeredTile.fit(1)).toList(),
if (modelCount != fittingCount) StaggeredTile.fit(CROSS_AXIS_COUNT)
],
children: [
...models.sublist(0, fittingCount).map((m) => ModelWidget(m)).toList(),
if (modelCount != fittingCount)
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList())
],
);
}),
),
// ------------------------------------------------------------------------
// ------------------------- solution (builder) ---------------------------
Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return StaggeredGridView.countBuilder(
crossAxisCount: CROSS_AXIS_COUNT,
shrinkWrap: true,
mainAxisSpacing: MAIN_AXIS_SPACING,
crossAxisSpacing: CROSS_AXIS_SPACING,
itemCount: modelCount == fittingCount ? fittingCount : fittingCount + 1,
itemBuilder: (context, index) {
if (index < fittingCount) {
return ModelWidget(models.elementAt(index));
} else {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: models.sublist(fittingCount, modelCount).map((m) {
return Container(
width: constraints.maxWidth / CROSS_AXIS_COUNT - CROSS_AXIS_SPACING,
child: ModelWidget(m));
}).toList());
}
},
staggeredTileBuilder: (int index) {
if (index < fittingCount) {
return StaggeredTile.count(1, 1);
} else {
return StaggeredTile.count(CROSS_AXIS_COUNT, 1);
}
});
}),
),
// ------------------------------------------------------------------------
],
),
),
),
),
);
}
}