3

When I run this code, the ListView will have an unexpected top padding. (See screenshot) Why is that and is there a way to avoid this?

I already tried SliverOverlapAbsorber, SafeArea and MediaQuery to fix the padding, but so far nothing seems to work.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (context, innerBoxIsScrolled) => [
          SliverAppBar(
            pinned: true,
            title: Text('Title'),
          ),
        ],
        body: ListView.builder(
          itemCount: 24,
          itemBuilder: (context, index) => Container(
            height: 40,
            alignment: Alignment.center,
            color: Colors.yellow,
            margin: EdgeInsets.only(top: index != 0 ? 8 : 0),
            child: Text('Body $index'),
          ),
        ),
      ),
    );
  }
}

enter image description here

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.2.3, on macOS 11.5.1 20G80 darwin-x64, locale de-DE)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.2)
[✓] IntelliJ IDEA Community Edition (version 2021.1.1)
[✓] VS Code (version 1.59.0)
[✓] Connected device (2 available)
Florian Bauer
  • 401
  • 5
  • 11

4 Answers4

7

As it seems there is no way to avoid manually removing the padding. So my solution now looks like this:

return Scaffold(
      body: DefaultTabController(
        length: 2,
        child: NestedScrollView(
          headerSliverBuilder: (context, innerBoxIsScrolled) => [
            SliverAppBar(
              pinned: true,
              title: Text('Title'),
              bottom: TabBar(tabs: [Tab(text: 'T 1'), Tab(text: 'T 2')]),
            ),
          ],
          body: MediaQuery.removePadding(
            removeTop: true,
            context: context,
            child: ListView.builder(
              itemCount: 24,
              itemBuilder: (context, index) => Container(
                height: 40,
                padding: EdgeInsets.zero,
                alignment: Alignment.center,
                color: Colors.yellow,
                margin: EdgeInsets.only(top: index != 0 ? 8 : 0),
                child: Text('Body $index'),
              ),
            ),
          ),
        ),
      ),
    );
Florian Bauer
  • 401
  • 5
  • 11
3

ListView adds some default padding, check documentation:

By default, ListView will automatically pad the list's scrollable extremities to avoid partial obstructions indicated by MediaQuery's padding. To avoid this behavior, override with a zero padding property.

You can easily get rid of it by adding a padding config the the builder, like this (you can add 0 but I don't recommend it):

body: ListView.builder(
  padding: const EdgeInsets.only(top: 8), // <-- add this line
  itemCount: 24,
  itemBuilder: (context, index) => Container(
    height: 40,
    alignment: Alignment.center,
    color: Colors.yellow,
    margin: EdgeInsets.only(top: index != 0 ? 8 : 0),
    child: Text('Body $index'),
  ),
),
Peter Koltai
  • 8,296
  • 2
  • 10
  • 20
  • Thanks for your answer, Peter. However, I wanted to avoid setting the padding directly. Especially since Dartpad does not show the padding, so I was not sure which behavior is actually correct. Btw. your solution would also remove the bottom padding, which should be kept. So I came up with a solution using MediaQuery.removePadding(...) around the ListView – Florian Bauer Aug 17 '21 at 17:00
  • You are welcome, good to hear it works. You are right, `removePadding` is better. – Peter Koltai Aug 17 '21 at 17:07
3

If you put ListView somewhere inside Scaffold having no appBar, ListView has top padding. There is no padding if appBar is present. There is no padding if you specify EdgeInsets.zero padding for ListView explicitly.

Aby Bermen
  • 162
  • 1
  • 6
  • Thanks for the info Aby. I was not aware about that behavior when the AppBar is missing. I now wrap the ListView with MediaQuery.removePadding(...) to avoid this. – Florian Bauer Aug 17 '21 at 17:06
0

MediaQuery.removePadding( context: context, removeTop: true,