flutterflutter-sliver

Is there a way to use ListView.Builder in a Column without shrinkwrap?


I'm attempting to place a ListView.builder inside a Column that is a peer to a SliverAppBar. Because of this I need to leverage a CustomScrollview and a SliverToBoxAdapter so that the Column can reside inside the CustomScrollView.

This all works fine as long as I set shrinkwrap to true.

But, for performance reasons I do not want to use shrinkwrap (per the official documentation, this is very expensive and negates the performance benefit of having the ListView.Builder lazy load the list items).

The Error is: "RenderFlex children have non-zero flex but incoming height constraints are unbounded". This is because the Column has infinite height.

I would like to not have to hard code the size of the Columns as this will be a responsive/adaptive scaffold.

My code is below - my question is, has anyone been able to use a Column with a ListView.Builder as a child without using shrinkwrap set to true and without hard coding the height?

import 'package:flutter/material.dart';

class TestScaffold extends StatelessWidget {
  const TestScaffold({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey[100],
      body: CustomScrollView(
        slivers: [
          SliverToBoxAdapter(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              mainAxisSize: MainAxisSize.min,
              children: [
                Expanded(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Text('Title 1'),
                      Expanded(
                        child: ListView.builder(
                          //shrinkWrap: true,
                          itemCount: 3,
                          itemBuilder: (context, index) {
                            return Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Container(
                                height: 100,
                                width: 100,
                                color: Colors.red,
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
                const SizedBox(
                  width: 10,
                ),
                Expanded(
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      const Text('Title 2'),
                      Expanded(
                        child: ListView.builder(
                          //shrinkWrap: true,
                          itemCount: 3,
                          itemBuilder: (context, index) {
                            return Padding(
                              padding: const EdgeInsets.all(8.0),
                              child: Container(
                                height: 100,
                                width: 100,
                                color: Colors.green,
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}


Solution

  • You can use SliverFillRemaining over Row while inner widget are using Expanded.

    class TestScaffold extends StatelessWidget {
      const TestScaffold({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.blueGrey[100],
          body: CustomScrollView(
            slivers: [
              SliverFillRemaining( //this
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Expanded(
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Text('Title 1'),
                          Expanded(
                            child: ListView.builder(
                              //shrinkWrap: true,
                              itemCount: 3,
                              itemBuilder: (context, index) {
                                return Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Container(
                                    height: 100,
                                    width: 100,
                                    color: Colors.red,
                                  ),
                                );
                              },
                            ),
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(
                      width: 10,
                    ),
                    Expanded(
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          const Text('Title 2'),
                          Expanded(
                            child: ListView.builder(
                              //shrinkWrap: true,
                              itemCount: 3,
                              itemBuilder: (context, index) {
                                return Padding(
                                  padding: const EdgeInsets.all(8.0),
                                  child: Container(
                                    height: 100,
                                    width: 100,
                                    color: Colors.green,
                                  ),
                                );
                              },
                            ),
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              )
            ],
          ),
        );
      }
    }
    

    I think you will Also like to use SliverPersistentHeader for your case.