flutterlistviewscrollscrollview

How to create a sticky text below a scrollable list in Flutter?


I am trying to display text directly below a list in Flutter, so that for a few items in the list there is no space between the list and the text. For many items, the text should remain visible at the bottom of the screen.

I was able to achieve this using React + Tailwind: https://codepen.io/mluttmann/pen/RwXNOPz

In Flutter, I got something similar, but because of the Expanded widget, the text sticks to the bottom of the screen when there are few items in the list. If I remove the Expanded widget and add shrinkWrap: true to the ListView builder, everything is fine with few items, but overflows with many items.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ItemListScreen(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('App'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: 30,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(title: Text('Item $index'));
              },
            ),
          ),
          const Text('This is some text below the list.'),
        ],
      ),
    );
  }
}

Solution

  • Instead of Expanded Widget use Flexible, like the following

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          home: ItemListScreen(),
        );
      }
    }
    
    class ItemListScreen extends StatelessWidget {
      const ItemListScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('App'),
          ),
          body: Column(
            mainAxisSize: MainAxisSize.min, 
            children: [
              NewWidget(),
              const Text('This is some text below the list.'),
            ],
          ),
        );
      }
    }
    
    class NewWidget extends StatelessWidget {
      const NewWidget({
        super.key,
      });
    
      @override
      Widget build(BuildContext context) {
        return Flexible(
          child: ListView.builder(
              shrinkWrap: true,
              itemCount: 30,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(title: Text('Item $index'));
              },
            ),
        );
      }
    }