Можно ли использовать несколько виджетов Scaffold на одной странице в Flutter?

Ответ

Технически можно, но это почти всегда плохая практика. Scaffold — это каркасный виджет, который предоставляет базовую структуру Material Design-страницы: AppBar, Drawer, BottomNavigationBar, FloatingActionButton и SnackBar. Несколько Scaffold в одной иерархии создают конфликты.

Проблемы при использовании нескольких Scaffold:

  • Конфликтующие ScaffoldMessengerSnackBar могут показываться в непредсказуемом месте
  • Наложение AppBar — несколько панелей инструментов запутают пользователя
  • Проблемы с навигациейNavigator может работать некорректно
  • Нарушение Material Design — противоречит принципам дизайна от Google

Когда это может быть оправдано (редко):

// Пример: модальный BottomSheet с собственной AppBar
void _showCustomSheet(BuildContext context) {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) => Scaffold(
      appBar: AppBar(
        title: Text('Детали'),
        automaticallyImplyLeading: false,
        actions: [
          IconButton(
            icon: Icon(Icons.close),
            onPressed: () => Navigator.pop(context),
          )
        ],
      ),
      body: ListView(
        children: [/* содержимое */],
      ),
    ),
  );
}

Правильные альтернативы для сложных интерфейсов:

// 1. Используйте CustomScrollView с SliverAppBar
CustomScrollView(
  slivers: [
    SliverAppBar(/* ... */),
    SliverList(/* ... */),
    // Еще один SliverAppBar для секции
    SliverAppBar(
      pinned: true,
      title: Text('Вторая секция'),
    ),
  ],
)

// 2. Вложенные Container с разными фонами
Column(
  children: [
    Container(
      color: Theme.of(context).appBarTheme.color,
      padding: EdgeInsets.all(16),
      child: Row(/* псевдо-AppBar */),
    ),
    Expanded(child: /* основное содержимое */),
  ],
)

В моих проектах я придерживаюсь правила: один Scaffold на один экран навигации. Для сложных макетов использую CustomScrollView, NestedScrollView или кастомные виджеты.

Ответ 18+ 🔞

А, ну это же классика, блядь! Слушай, тут народ частенько спрашивает: а можно ли запихнуть один Scaffold в другой? Технически-то можно, ёпта, компилятор не заругается. Но это будет такая же пиздопроебибна, как пытаться надеть два шлема сразу — голова вроде и защищена, но нихуя не видно и выглядишь как полный ебанько.

Вот на какие грабли ты наступишь, если начнёшь плодить Scaffold-ы:

  • ScaffoldMessenger нихуя не поймёт. Твой SnackBar может вылезти где угодно: на втором этаже, в соседнем подъезде, а пользователь будет сидеть и думать: «Чё за хуйня, где моё сообщение?».
  • AppBar на AppBar-е. Представь, у тебя две панели инструментов торчат одна над другой. Пользователь охуеет и просто снесёт приложение к хуям.
  • Навигация сломается в хлам. Navigator запутается, как пьяный в трёх соснах, и начнёт ронять страницы куда попало.
  • Material Design в ахуе. Гугловские дизайнеры смотрят на такое и плачут. Это как прийти в театр в трусах и каске — технически ты одет, но всем похуй, ты идиот.

Хотя, блядь, есть один хитрый случай, где это не так уж и тупо:

// Допустим, тебе надо выкатить модалку снизу, но чтоб у неё была своя шапка
void _showCustomSheet(BuildContext context) {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) => Scaffold( // Второй Scaffold ТОЛЬКО внутри модалки!
      appBar: AppBar(
        title: Text('Детали'),
        automaticallyImplyLeading: false,
        actions: [
          IconButton(
            icon: Icon(Icons.close),
            onPressed: () => Navigator.pop(context),
          )
        ],
      ),
      body: ListView(
        children: [/* содержимое */],
      ),
    ),
  );
}

Но если тебе просто хочется сложную хуйню с кучей скроллов и секций — делай по-человечески:

// 1. Кастомные скроллы — твой лучший друг
CustomScrollView(
  slivers: [
    SliverAppBar(/* ... */), // Первая липкая шапка
    SliverList(/* ... */),   // Основной контент
    // И вот ещё одна секция со своей шапкой
    SliverAppBar(
      pinned: true,
      title: Text('Вторая секция'),
    ),
  ],
)

// 2. Просто контейнеры, Карл!
Column(
  children: [
    Container(
      color: Theme.of(context).appBarTheme.color,
      padding: EdgeInsets.all(16),
      child: Row(/* делаем вид, что это AppBar */),
    ),
    Expanded(child: /* а тут уже основное тело */),
  ],
)

Короче, запомни, как «Отче наш»: один экран — один Scaffold. Не выёбывайся. Для всего остального есть CustomScrollView и голова на плечах, чтобы думать, а не просто впендюривать виджеты друг в друга.