← Назад к вопросам
Можно ли в пределах одной страницы использовать несколько Scaffold?
1.0 Junior🔥 131 комментариев
#Flutter виджеты
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Можно ли использовать несколько Scaffold на одной странице?
Это частый вопрос на собеседованиях. Ответ: Технически можно, но это BAD PRACTICE в большинстве случаев. Рассмотрю когда это допустимо и почему избегать.
Что такое Scaffold?
Scaffold — это контейнер, который предоставляет стандартный материальный дизайн макет с:
- AppBar (заголовок)
- Body (основной контент)
- FloatingActionButton (плавающая кнопка)
- BottomNavigationBar (нижняя навигация)
- Drawer (боковое меню)
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('My Page')),
body: Center(child: Text('Hello')),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
);
}
}
❌ Несколько Scaffold — Плохо
1. Дублирование структуры
// ❌ НЕ ДЕЛАЙ ТАК
class BadMultipleScaffold extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Top AppBar')),
body: Scaffold( // Вложенный Scaffold — плохая идея!
appBar: AppBar(title: Text('Inner AppBar')),
body: Center(child: Text('Content')),
),
);
}
}
Проблемы:
- Два AppBar займут место (смотрится странно)
- Конфликт обработки событий (back button)
- Усложнение CSS (стиля), доступности
2. Конфликт FloatingActionButton
// ❌ Какой FAB будет виден?
class BadFABs extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => print('Outer FAB'),
child: Icon(Icons.add),
),
body: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () => print('Inner FAB'),
child: Icon(Icons.edit),
),
body: Center(child: Text('Content')),
),
);
}
}
// Результат: конфликты и непредсказуемое поведение
3. Проблемы с навигацией
// ❌ Back button не работает правильно
class BadNavigation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Outer Page'),
leading: BackButton(), // Какой Scaffold он закроет?
),
body: Scaffold(
appBar: AppBar(title: Text('Inner Page')),
body: Center(child: Text('Confusing UI')),
),
);
}
}
✅ Правильные подходы
1. Один Scaffold, несколько виджетов в body
// ✅ ПРАВИЛЬНО
class ProperPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('My Page')),
body: SingleChildScrollView(
child: Column(
children: [
// Первая секция
Container(
padding: EdgeInsets.all(16),
child: Text('Section 1'),
),
// Вторая секция
Container(
padding: EdgeInsets.all(16),
child: Text('Section 2'),
),
// Третья секция
Container(
padding: EdgeInsets.all(16),
child: Text('Section 3'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => print('One FAB for all'),
child: Icon(Icons.add),
),
);
}
}
2. Использование TabBar для разных экранов
// ✅ ПРАВИЛЬНО — Один Scaffold с TabBarView
class TabbedPage extends StatefulWidget {
@override
State<TabbedPage> createState() => _TabbedPageState();
}
class _TabbedPageState extends State<TabbedPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Tabbed Page'),
bottom: TabBar(
controller: _tabController,
tabs: [
Tab(text: 'Tab 1'),
Tab(text: 'Tab 2'),
Tab(text: 'Tab 3'),
],
),
),
body: TabBarView(
controller: _tabController,
children: [
Center(child: Text('Content 1')),
Center(child: Text('Content 2')),
Center(child: Text('Content 3')),
],
),
);
}
}
3. Несколько страниц через Navigator (правильный способ)
// ✅ ПРАВИЛЬНО — Разные Scaffold на разных страницах
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(
child: ElevatedButton(
onPressed: () {
// Переход на другую страницу с собственным Scaffold
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailsPage()),
);
},
child: Text('Go to Details'),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold( // Другой Scaffold для другой страницы
appBar: AppBar(
title: Text('Details'),
automaticallyImplyLeading: true, // Back button
),
body: Center(child: Text('Details content')),
);
}
}
✅ РЕДКИЕ случаи когда несколько Scaffold допустимы
1. BottomSheet с собственным контентом
// ⚠️ Условно допустимо — но лучше использовать showModalBottomSheet
class PageWithBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Main Page')),
body: Center(
child: ElevatedButton(
onPressed: () {
// ✅ Правильный способ — showModalBottomSheet
showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 300,
child: Center(child: Text('Bottom Sheet')),
),
);
},
child: Text('Show Bottom Sheet'),
),
),
);
}
}
2. Dialog с собственным Scaffold (очень редко)
// ⚠️ Очень редкий случай — Full screen dialog
class PageWithDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Main')),
body: Center(
child: ElevatedButton(
onPressed: () {
// ✅ Лучше использовать showGeneralDialog или Navigator
Navigator.of(context, rootNavigator: true).push(
MaterialPageRoute(
fullscreenDialog: true, // Полноэкранный диалог
builder: (context) => Scaffold(
appBar: AppBar(title: Text('Dialog')),
body: Center(child: Text('Dialog content')),
),
),
);
},
child: Text('Show Dialog'),
),
),
);
}
}
Сравнение подходов
| Подход | Используй когда | Пример |
|---|---|---|
| Один Scaffold + Column | Несколько секций на одной странице | Профиль пользователя |
| Scaffold + TabBarView | Несколько независимых вкладок | Gmail (Mail, Contacts, etc) |
| Navigator + разные Scaffold | Разные экраны приложения | Home → Details → Settings |
| showModalBottomSheet | Временная информация | Фильтры, меню |
| fullscreenDialog | Полноэкранный диалог | Создание объекта |
Практический пример: Правильная архитектура
// ✅ Правильная структура
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
);
}
}
class MainPage extends StatefulWidget {
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _currentIndex = 0;
final _pages = [
HomePage(),
SearchPage(),
ProfilePage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
// Один главный Scaffold
appBar: AppBar(title: Text('My App')),
body: _pages[_currentIndex], // Разные виджеты, но один Scaffold
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
],
),
);
}
}
class HomePage extends Widget {
// ✅ Нет собственного Scaffold!
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(children: [
// Контент
]),
);
}
}
Резюме
Вопрос: Можно ли использовать несколько Scaffold?
Ответ: Технически можно, но НЕ НУЖНО в 99% случаев.
Правило:
- Одна страница = один Scaffold
- Несколько экранов = несколько Scaffold (на разных страницах через Navigator)
- Несколько секций = один Scaffold + Column/ListView в body
- Modal content = showModalBottomSheet / showDialog (без Scaffold)
Best Practice:
- Используй один Scaffold для основного макета
- Разные страницы приложения = разные Scaffold через Navigator
- Модальные окна через showModalBottomSheet, showDialog, fullscreenDialog
- Вложенные Scaffold = признак неправильной архитектуры