NestedScrollView с SliverAppBar вызывает неожиданное заполнение тела

Когда я запускаю этот код, у ListView будет неожиданное заполнение сверху. (См. Снимок экрана) Почему это так и есть ли способ этого избежать?

Я уже пробовал SliverOverlapAbsorber, SafeArea и MediaQuery, чтобы исправить отступы, но пока ничего не работает.

      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'),
          ),
        ),
      ),
    );
  }
}

      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)

4 ответа

Кажется, нет никакого способа избежать ручного удаления прокладки. Итак, мое решение теперь выглядит так:

      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'),
              ),
            ),
          ),
        ),
      ),
    );

ListViewдобавляет отступы по умолчанию, проверьте документацию :

По умолчанию ListView автоматически дополняет прокручиваемые края списка, чтобы избежать частичных препятствий, обозначенных заполнением MediaQuery. Чтобы избежать этого поведения, переопределите свойство нулевого заполнения.

Вы можете легко избавиться от него, добавив padding сконфигурируйте построитель следующим образом (вы можете добавить 0, но я не рекомендую это делать):

      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'),
  ),
),

Если вы поместите ListView где-нибудь внутри Scaffold без appBar, ListView будет иметь верхнее заполнение. Если присутствует appBar, отступов нет. Если явно указать заполнение EdgeInsets.zero для ListView, заполнение отсутствует.

MediaQuery.removePadding(контекст: контекст,removeTop: правда,

Другие вопросы по тегам