简体   繁体   中英

Flutter listview within listview not scrolling

As my first Flutter project I'm building an app for a newspaper. There are a number of news categories. For those categories, I have created a generic Widget , in the home screen that Widget will be shown multiple times for multiple categories in a Listview , those category Widgets have Listview in them too as I bring multiple news from those categories. The Widget class that has this generic Widget is Newsfeed.dart which will be given below.

This generic Widget is called from a another Widget class WidgetFactory.dart which actually calls API and builds the home screen by using the above mentioned generic Widget for categories. This class uses a Listview.builder which is inside FutureBuilder .

The problem is, when I open the app in the screen the news appears but I can't scroll, it stays fixed. I have checked if the API is actually bringing the news, in console I have printed the API response, all of the news are fetched but still I can't scroll.

the flow is main.dart -> WidgetFactory() -> Newsfeed()

WidgetFactory()

class WidgetFactory extends StatefulWidget {
  @override
  _WidgetFactoryState createState() => _WidgetFactoryState();
}

class _WidgetFactoryState extends State<WidgetFactory> {
  List homeScreenCategories = [4, 14, 13, 23, 8015, 22];

  Future<List> newsPostList;
  List<List<NewsPost>> categoryNewsPostList;

  @override
  void initState() {
    super.initState();

    newsPostList = fetchNews();
  }

  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);

    return Container(
      alignment: Alignment.center,
      child: Container(
        child: RefreshIndicator(
            child: FutureBuilder(
              future: newsPostList,
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                if(snapshot.data == null) {
                  return Container(
                      child: CircularProgressIndicator()
                  );
                } else {
                  return ListView.builder(
                    shrinkWrap: true,
                    physics: const AlwaysScrollableScrollPhysics(),
                    itemCount: snapshot.data.length,
                    itemBuilder: (BuildContext context, int index) {
                      return _getCategoryNews(snapshot, index);
                    },
                  );

                }
              },
            ),
            onRefresh: () {
              fetchNews();
            }
        ),
      ),
    );
  }

  Future<List> fetchNews() async {
    String url = "url";
    Response response = await Dio().get(url);

    if(response.statusCode == 200) {
      List newsPostList = [];

      for(int i=0; i<response.data.length; i++) {
        newsPostList.add(response.data[i]);
      }
      return newsPostList;
    } else {
      throw Exception("Failed to fetch category");
    }
  }

  Widget _getCategoryNews(snapshot, int index) {
    List<NewsPost> newsPostList = [];

    for(var c in snapshot.data[index]['items']) {
      NewsPost newsPost = NewsPost.getNewsPostFromAPI(c);
      newsPostList.add(newsPost);
    }
    return Newsfeed(newsPostList, "National");
  }
}

Newsfeed()

class Newsfeed extends StatefulWidget {
  String categoryName;

  List<NewsPost> newsPostList;

  Newsfeed(this.newsPostList, this.categoryName);
  @override
  _NewsfeedState createState() => _NewsfeedState(this.newsPostList, this.categoryName);
}

class _NewsfeedState extends State<Newsfeed> {
  final GlobalKey<ScaffoldState> _scaffoldKeyTwo = new GlobalKey<ScaffoldState>(debugLabel: '_MainScreenKey');

  String categoryName;

  _NewsfeedState(this.newsPostList, this.categoryName);

  List<NewsPost> newsPostList;

  var dio = new Dio();

  @override
  void initState() {
   super.initState();
  }

  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Container(
      alignment: Alignment.center,
      child: ListView.builder(
          shrinkWrap: true,
          itemCount: newsPostList.length,
          itemBuilder: (BuildContext context, int index) {
            print(newsPostList[index]);
            return _getNewsPostWidgets(index);
          }
      ),
    );

  }

  Widget _getNewsPostWidgets(int index) {
    var newsPost = newsPostList[index];

    if(index < 5) {
      if(index == 0) {
        return GestureDetector(
            onTap: () {
              Navigator.push(
                  context,
                  ScaleTransitionRoute(
                      page: NewsPostDetails(newsPostList, index)
                  )
              );
            },
            child: Column(
              children: <Widget>[
                Container(
                  padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
                  //constraints: BoxConstraints(minWidth: double.infinity, maxWidth: double.infinity),
                  constraints: BoxConstraints.expand(
                      width: double.infinity,
                      height: 40
                  ),
                  color: const Color(0xFF2b4849),
                  child: Text(
                    this.categoryName,
                    style: TextStyle(
                        fontSize: 33,
                        color: Colors.white
                    ),
                  ),
                ),
                BlockHeadline(newsPost)
              ],
            )
        );
      }
      else {
        return GestureDetector(
          onTap: () {
            Navigator.push(
                context,
                ScaleTransitionRoute(
                    page: NewsPostDetails(newsPostList, index)
                )
            );
          },
          child: ListedNews(newsPost),
        );
      }
    }
    else {
      return Container(
        color: const Color(0xFF2b4849),
        child: index == 5 ? FlatButton(
          child: Text(
            "See More",
            style: TextStyle(
                color: Colors.white
            ),
          ),
          onPressed: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (BuildContext context) => NewsFeedForSpecificCategory(newsPostList)
                )
            );
          },
        ) : Container(),
      );
    }
  }

  openNewsPostDetails(List<NewsPost> newsPostList, int index) {
    Navigator.push(
        context,
        ScaleTransitionRoute(
            page: NewsPostDetails(newsPostList, index)
        )
    );
  }
}

What I have tried

I found some questions that relates to this problem a bit. Tried those.

  1. I used shrinkwrap=true in my Listview.builder , but of no use.
  2. Tried using Column inside SingleChildScrollView() , still did not work.
  3. Inside the Listview.builder added physics as AlwaysScrollable() , also in vain.

As I'm new to flutter what I tried might seem dumb.

One more thing is, the news that shows up in the home screen, that takes me to the details page fine and there swiping left right takes me to other news also. It's the home screen that is causing trouble, not scrolling.

It would be great help if you could kindly give some clues.

Putting ListView inside ListView is an anti pattern.

There are several solutions for this problem,

Solution 1:

Merge those two list of items into a single list of items and display it as a single ListView.

Solution 2:

You can use SliverList for your use case. SliverList can wrap multiple SliverLists inside a single CustomScrollView.

I have found the solution to this problem. It was quite simple actually.

In the build() method of my _NewsfeedState class I have added ClampingScrollPhysics() as physics .

@override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return Container(
      alignment: Alignment.center,
      child: ListView.builder(
          shrinkWrap: true,
          physics: ClampingScrollPhysics(),
          itemCount: newsPostList.length,
          itemBuilder: (BuildContext context, int index) {
            print(newsPostList[index]);
            return _getNewsPostWidgets(index);
          }
      ),
    );

  }

It worked.

This will help you.

  child: ListView.builder(
    physics: NeverScrollableScrollPhysics(),

Thanks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM