一起滚动屏幕和列表视图,而不是单独滚动

Posted

技术标签:

【中文标题】一起滚动屏幕和列表视图,而不是单独滚动【英文标题】:Scroll the screen and listview together, NOT seperately 【发布时间】:2021-10-29 06:08:39 【问题描述】:

我已经看过这些答案here,但它们对我不起作用。我希望 LatestNewsList 小部件和整个屏幕一起滚动而不是单独滚动。这是屏幕的代码:

class Search extends StatelessWidget 
  final tab = new TabBar(tabs: <Tab>[
    new Tab(icon: new Icon(Icons.arrow_forward)),
    new Tab(icon: new Icon(Icons.arrow_downward)),
    new Tab(icon: new Icon(Icons.arrow_back)),
  ]);

  @override
  Widget build(BuildContext context) 
    final bloc = LatestNewsProvider.of(context);

    return DefaultTabController(
        length: 6,
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Container(
                margin: EdgeInsets.only(
                  // right: 10,
                  left: 10,
                  top: 20,
                ),
                child: Row(
                  children: [
                    Container(
                      width: 32,
                      height: 32,
                      child: CircleAvatar(
                        backgroundImage: NetworkImage(
                            'https://thispersondoesnotexist.com/image'),
                      ),
                    ),
                    SizedBox(
                      width: 20,
                    ),
                    SearchBar(),
                  ],
                ),
              ),
              Container(
                child: TabBar(
                    isScrollable: true,
                    unselectedLabelColor: Colors.black,
                    labelColor: Colors.blue,
                    tabs: [
                      Tab(
                        text: "Latest",
                      ),
                      Tab(text: "programming"),
                      Tab(text: "general"),
                      Tab(text: "sports"),
                      Tab(text: "academia"),
                      Tab(text: "politics"),
                    ]),
              ),
              Container(
                //Add this to give height
                height: MediaQuery.of(context).size.height,
                child: TabBarView(children: [
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.fetchLatestNews();
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.newsStream),
                              LatestNewsList(bloc, bloc.newsStream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.c1Fetch('programming');
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.c1Stream),
                              LatestNewsList(bloc, bloc.c1Stream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.c2Fetch('general');
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.c2Stream),
                              LatestNewsList(bloc, bloc.c2Stream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.c3Fetch('sports');
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.c3Stream),
                              LatestNewsList(bloc, bloc.c3Stream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.c4Fetch('academia');
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.c4Stream),
                              LatestNewsList(bloc, bloc.c4Stream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                  Column(
                    children: [
                      StreamBuilder(
                        stream: bloc.searchedListBuilderStream,
                        builder: (context, snapshot) 
                          if (snapshot.hasData) 
                            return NewsListBuilder(snapshot);
                           else if (snapshot.hasError) 
                            return Text('No results found');
                          
                          bloc.c5Fetch('politics');
                          return Expanded(
                              child: Column(
                            children: [
                              HorizontalSearchList(bloc, bloc.c5Stream),
                              LatestNewsList(bloc, bloc.c5Stream, 'Search'),
                            ],
                          ));
                        ,
                      )
                    ],
                  ),
                ]),
              ),
            ],
          ),
        ));
  

LatestNewsList 小部件内部有一个小部件,该小部件具有负责构建列表视图的代码:

class NewsListBuilder extends StatelessWidget 
  final snapshot;

  NewsListBuilder(this.snapshot);

  @override
  Widget build(BuildContext context) 
    return Expanded(
        child: ListView.builder(
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
      scrollDirection: Axis.vertical,
      padding: EdgeInsets.all(8),
      itemCount: snapshot.data.length,
      itemBuilder: (BuildContext context, int index) 
        return NewsListBuilderItems(snapshot, index);
      ,
    ));
  

我无法继续滚动:

【问题讨论】:

【参考方案1】:

对于像您这样的更复杂的滚动页面,您应该使用 slivers。在此处阅读有关它们的更多信息:https://flutter.dev/docs/development/ui/advanced/slivers

我可以为您提供一个简化的示例,说明您想做什么(希望我理解正确):

import 'package:flutter/material.dart';

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Search(),
    );
  


class Search extends StatefulWidget 
  @override
  _SearchState createState() => _SearchState();


class _SearchState extends State<Search> with SingleTickerProviderStateMixin 
  late final TabController _tabController;

  @override
  void initState() 
    // Make sure to set the correct length
    _tabController = TabController(length: 5, vsync: this);

    super.initState();
  


  @override
  Widget build(BuildContext context) 
    return NestedScrollView(
      headerSliverBuilder: (context, innerBoxIsScrolled) 
        return [
          SliverAppBar(
            title: Container(height: 40, color: Colors.grey), // this can be the search bar
            bottom: TabBar(
              indicatorWeight: 3,
              indicatorPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
              controller: _tabController,
              tabs: <Widget>[
                Tab(text: "programming"),
                Tab(text: "general"),
                Tab(text: "sports"),
                Tab(text: "academia"),
                Tab(text: "politics"),
              ],
            ),
          ),
        ];
      ,
      body: TabBarView(
        controller: _tabController,
        children: [
          /// here you put all your pages

          // Example of one page
          // You will need to wrap this in StreamBuilder as you do in the
          // original code
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate((context, index) 
                  return Container(
                    height: 400,
                    color: Colors.red.shade200,
                    margin: EdgeInsets.all(4),
                  );
                ),
              ),
            ],
          ),
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate((context, index) 
                  return Container(
                    height: 400,
                    color: Colors.green,
                    margin: EdgeInsets.all(4),
                  );
                ),
              ),
            ],
          ),
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate((context, index) 
                  return Container(
                    height: 400,
                    color: Colors.blue,
                    margin: EdgeInsets.all(4),
                  );
                ),
              ),
            ],
          ),
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate((context, index) 
                  return Container(
                    height: 400,
                    color: Colors.blue,
                    margin: EdgeInsets.all(4),
                  );
                ),
              ),
            ],
          ),
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate((context, index) 
                  return Container(
                    height: 400,
                    color: Colors.blue,
                    margin: EdgeInsets.all(4),
                  );
                ),
              ),
            ],
          ),
        ],
      ),
    );
  


【讨论】:

它以某种方式工作,但并不完全。你在哪里评论 /// 当我这样做时,你把所有的标签放在你的页面上,列表视图消失了 @Benyamin, PageView 在这种情况下与您帖子中的TabBarView 的工作方式类似。您可以横向滑动(或单击选项卡)以在页面之间导航。您需要为每个类别(编程、一般、运动等)添加一个 CustomScrollView 页面。这些页面必须像在原始代码中一样被包裹在 StreamBuilders 中。 如何在标签栏顶部添加头像和搜索栏? @Benyamin,您可以将其与bottom 的 TabBar 放在一列中。我会更新答案 我不知道bottom 参数需要特定的小部件,抱歉。您仍然可以改用title。当我弄清楚其他问题时,我会更新答案

以上是关于一起滚动屏幕和列表视图,而不是单独滚动的主要内容,如果未能解决你的问题,请参考以下文章

如何检查列表视图页脚是不是在屏幕中滚动

如何使用具有不同滚动方向的多个collectionview滚动整个屏幕

自定义滚动谷歌颤动中的水平列表视图

滚动视图无法执行委托,但表视图可以

列表视图滚动时在屏幕底部隐藏线性布局

相对布局内的列表视图和滚动视图不覆盖屏幕