如何使ListView小部件永久地与AppBar底部相邻?
我现在正在构建我的应用程序,并且遇到了一个问题,那就是试图让我的ListView芯片部件的行为类似于YouTube应用程序主页上标签的行为。 对于那些不熟悉的人来说,YouTube移动应用程序有一种ListView小部件,它包含一些标签来过滤你主页上的视频,我在文章底部添加了这些标签 看起来AppBar与它下面的实际水平ListView是分开的,但无论何时出现(这似乎是某种滑动AppBar行为),它都会出现,好像不知何故被固定在它上面。 有没有一种很好的方法可以在不使用AppBar的“bottom”属性的情况下实现这一点,或者使用bottom特性,但仍然使用边框/阴影分隔两个小部件 具体地说,我正在寻找这种情况下的最佳实践,因为我对颤振还不熟悉,因此不想做出低于标准的解决方案 谢谢如何使ListView小部件永久地与AppBar底部相邻?,listview,flutter,appbar,Listview,Flutter,Appbar,我现在正在构建我的应用程序,并且遇到了一个问题,那就是试图让我的ListView芯片部件的行为类似于YouTube应用程序主页上标签的行为。 对于那些不熟悉的人来说,YouTube移动应用程序有一种ListView小部件,它包含一些标签来过滤你主页上的视频,我在文章底部添加了这些标签 看起来AppBar与它下面的实际水平ListView是分开的,但无论何时出现(这似乎是某种滑动AppBar行为),它都会出现,好像不知何故被固定在它上面。 有没有一种很好的方法可以在不使用AppBar的“botto
我使用了一个
CustomScrollView
,两个SliverAppBar
一个接一个出现(第一个包含YouTube徽标,第二个包含ChoiceChip
小部件列表)
这就是你需要的。唯一的问题是我无法解决设置应用程序栏高度的问题。它比YouTube上的那个太高了。设置minimumHeight
的功能看起来像是在研究:
我使用了一个
CustomScrollView
,两个SliverAppBar
相继出现(第一个包含YouTube徽标,第二个包含ChoiceChip
小部件列表),从而得出了这个解决方案
这就是你需要的。唯一的问题是我无法解决设置应用程序栏高度的问题。它比YouTube上的那个太高了。设置minimumHeight
的功能看起来像是在研究:
非常感谢。我最终使用了Stack作为脚手架的主体,这样我就可以在我想保持不动的小部件下面放置一个可滚动的文件。@BenShabtai有趣,你能分享你的解决方案吗?我很好奇。我不想这么做,因为这是我正在做的一个项目的一部分,但它真的很简单。只需使用Stack小部件将chips小部件放在可滚动的“上方”,并使用定位小部件将chips小部件放在容器顶部。我希望这能帮你解决这个问题,如果不行,我会尝试为你复制一份代码,而不暴露重要的部分。谢谢!我最终使用了Stack作为脚手架的主体,这样我就可以在我想保持不动的小部件下面放置一个可滚动的文件。@BenShabtai有趣,你能分享你的解决方案吗?我很好奇。我不想这么做,因为这是我正在做的一个项目的一部分,但它真的很简单。只需使用Stack小部件将chips小部件放在可滚动的“上方”,并使用定位小部件将chips小部件放在容器顶部。我希望这能为您解决问题,如果不能,我将尝试为您制作一份代码副本,而不暴露重要的部分。
int _selectedIndex = 0;
List<String> chipTitles = [
'Broski',
'Atom',
'Elon Musk',
'Lemonade',
'Ginger',
'Tiger',
'Drama',
'Comedy',
'COVID-19',
'US'
];
SliverAppBar(
pinned: true,
floating: false,
expandedHeight: 50.0,
flexibleSpace: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: chipTitles.length,
separatorBuilder: (context, index) => SizedBox(
width: 10.0,
),
itemBuilder: (context, index) {
return ChoiceChip(
selected: _selectedIndex == index,
label: Text('${chipTitles[index]}'),
onSelected: (selected) {
if (selected) {
setState(() {
_selectedIndex = index;
});
}
},
);
},
),
),
class ScrollerDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ScrollerDemoState();
}
class _ScrollerDemoState extends State<ScrollerDemo> {
int _selectedIndex = 0;
List<String> chipTitles = [
'Broski',
'Atom',
'Elon Musk',
'Lemonade',
'Ginger',
'Tiger',
'Drama',
'Comedy',
'COVID-19',
'US'
];
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
const SliverAppBar(
// Results in the logo app bar mimicking the one used in the YouTube app.
pinned: false,
floating: true,
expandedHeight: 80.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('CustomScrollView Demo'),
),
),
SliverAppBar(
pinned: true,
floating: false,
expandedHeight: 50.0,
flexibleSpace: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: chipTitles.length,
separatorBuilder: (context, index) => SizedBox(
width: 10.0,
),
itemBuilder: (context, index) {
return ChoiceChip(
selected: _selectedIndex == index,
label: Text('${chipTitles[index]}'),
onSelected: (selected) {
if (selected) {
setState(() {
_selectedIndex = index;
});
}
},
);
},
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
childAspectRatio: 4.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('Grid item $index'),
);
},
childCount: 20,
),
),
SliverFixedExtentList(
itemExtent: 50.0,
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
alignment: Alignment.center,
color: Colors.lightBlue[100 * (index % 9)],
child: Text('List item $index'),
);
},
childCount: 36,
),
),
],
);
}
}