如何使ListView小部件与AppBar底部永久相邻?

问题描述 投票:1回答:1

我正在构建我的应用程序,遇到了一个问题,即试图使我的Chips的ListView小部件的行为类似于标记在YouTube应用程序主页上的行为。对于不熟悉的用户,YouTube移动应用程序具有一种ListView小部件,其中包含一些用于过滤您首页上的视频的标签,我已在文章底部添加了该标签。

看来AppBar与位于其下方的实际水平ListView是分开的,但只要它出现就出现(似乎是SliverAppBar的某种行为,看起来),就像它被某种方式卡在了它上一样。是否有一种不使用AppBar的'bottom'属性或使用底部特征但仍用边框/阴影分隔两个小部件的好方法呢?

[特别是,我正在寻找这种情况下的最佳实践,因为我是Flutter的新手,因此不想提出低于标准的解决方案。

谢谢!

YouTube labels ListView.

listview flutter appbar
1个回答
0
投票

[我使用CustomScrollView到达此解决方案,其中两个SliverAppBar依次出现(第一个包含YouTube徽标,第二个包含ChoiceChip小部件列表)。

SliverAppBar with a ListView consisting of ChoiceChips

这就是您需要的。唯一的问题是我无法解决设置应用栏高度的问题。与YouTube中的那个相比太高了。设置minimumHeight的功能似乎正在研究this PR

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

还包括完整的StatefulWidget类作为完整示例:

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,
          ),
        ),
      ],
    );
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.