0

1. The Problem

How do I make my ListView.builder be able to scroll to empty space both to the top and to the bottom?

For example, I have a list of custom widgets, and I would like the user to be able to get the top card on the list — which is at the top of the screen — closer to his thumb by scrolling to it, while Flutter renders the top space with an empty background.

2. What I've tried so far

The basic shape of my code is a basic implementation of the ListView.builder constructor:

ListView.builder(
  itemCount: widgetsList.length,
  itemBuilder: (context, index){
    return widgetsList[index];
  },
),

I've tried fiddling with some of the ListView.builder's properties and also some workarounds so far:

  1. At first, I thought that either shrinkWrap: true or physics: AlwaysScrollableScrollPhysics() — maybe I have to set the parent parameter of AlwaysScrollableScrollPhysics()? — would do the job, but none of them seem to work.
  2. I've also tried to do this artifially by creating empty Containers both on the top and the bottom of the list, and adding something like dragStartBehavior: DragStartBehavior.values[1] — I don't think that's how you use the .values property actually — to make the list start from the second value, but it didn't work.
Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76

2 Answers2

2

If I understand it correctly, your best bet would be using a CustomScrollView with an expandable space in the SliverAppBar.

Widget build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(
      slivers: [
         SliverAppBar(
           automaticallyImplyLeading: false, // gets rid of the back arrow
           expandedHeight: 250, // the collapsible space you want to use 
           flexibleSpace: FlexibleSpaceBar(
             background: Container(
               color: Colors.transparent
             ),
           ),
         ),
         SliverList(
          delegate: SliverChildBuilderDelegate(
            (context, index) {
              // put your widgetsList here
            },
            childCount: widgetsList.length,
          ),
        ),
      ]
    ),
  );
}
Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76
nicowernli
  • 3,250
  • 22
  • 37
  • The behavior of the `SliverAppBar` is apparently what I want, where the box seems flexible to go up and down in height. But how to I render my list of widgets (cards) inside of the `FlexibleSpaceBar`? – Philippe Fanaro Nov 13 '19 at 15:16
  • Your list comes after the `FlexibleSpaceBar`, you use the `SliverList` inside of the `(context, index) {}` – nicowernli Nov 13 '19 at 15:17
  • But that would render my scrollable list below the box with flexible height you've just designed, which is not what I had in mind. – Philippe Fanaro Nov 13 '19 at 15:20
  • Do you have a preview of what do you want to achieve? – nicowernli Nov 13 '19 at 15:27
  • There isn't much to it, it's just having `Flutter` fill the top with empty space when trying to make the first item of the `ListView` get to the bottom of the screen. [Here](https://imgur.com/a/5TwTBSH) is something I did with `Adobe XD` that might be of help. – Philippe Fanaro Nov 13 '19 at 16:14
  • After messing around with it, this actually does seem to work, and I intend to maybe edit your code to have it closer to what I wanted originally. I just used one `SliverAppBar` at the top and another at the bottom. But two problems I'm having right now are: (1) how to disable the blurring effect of the top `SliverAppBar` when it's collapsing? (2) how do I start the page scroll from the cards and not the first `SliverAppBar`? – Philippe Fanaro Nov 13 '19 at 17:07
  • Another question I have, related to your answer, is [this one](https://stackoverflow.com/q/58884360/4756173). – Philippe Fanaro Nov 15 '19 at 21:46
1

That is possible to be achived with your "Container workaround". You could use a ScrollController and have its initialScrollOffset where the top Container ends. It is something I only later found out through this other StackOverflow question.

  1. Declare your ScrollController inside your widget's class.
    ScrollController scrollController = ScrollController(
      initialScrollOffset: 10, // or whatever offset you wish
      keepScrollOffset: true,
    );
    
  2. Add the controller to your ListView
    ListView.builder(
      controller: scrollController,
      itemCount: widgetsList.length,
      itemBuilder: (context, index){
        return widgetsList[index];
      },
    ),
    

Additionally, you may even want to create animations for the background scrolling action. That is possible through using the .animateTo method inside your widget's initState.

Philippe Fanaro
  • 6,148
  • 6
  • 38
  • 76