Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Scaffold в Flutter: применение и лучшие практики
Scaffold — это один из самых используемых widgets в Flutter Material Design. Это контейнер, который реализует базовую визуальную структуру Material приложения.
Что такое Scaffold и зачем он нужен
Scaffold предоставляет инфраструктуру для Material Design компонентов:
Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(child: Text('Content')),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
drawer: Drawer(),
bottomNavigationBar: BottomNavigationBar(),
)
Основные свойства
AppBar — верхняя панель приложения:
- Заголовок страницы
- Иконки действий
- Кнопка "назад" (автоматически)
- Состояние приложения (батарея, время, сигнал)
Body — основное содержимое:
- Главной контент экрана
- Всегда занимает оставшееся пространство
- Может быть любым widget'ом
FloatingActionButton — кнопка действия:
- Плавающая кнопка внизу справа
- Primary action для экрана
- Используется для главного действия (add, compose, call)
Drawer — боковое меню:
- Material Design навигация
- Свайп слева направо или тап иконки
- Список меню пунктов
BottomNavigationBar — навигация снизу:
- Переключение между основными секциями
- Макс 5 пунктов (best practice)
- Показывает активный tab
Практические примеры
Пример 1: Простой экран с AppBar и FloatingActionButton
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
elevation: 0,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Clicks:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => _counter++),
child: Icon(Icons.add),
),
);
}
}
Пример 2: Scaffold с Drawer навигацией
class AppShell extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My App'),
// Иконка гамбургера автоматически добавляется если есть drawer
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: BoxDecoration(color: Colors.blue),
child: Text('Menu', style: TextStyle(color: Colors.white)),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Settings'),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, '/settings');
},
),
],
),
),
body: Center(child: Text('Home page')),
);
}
}
Пример 3: Scaffold с BottomNavigationBar
class MainApp extends StatefulWidget {
@override
State<MainApp> createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
int _selectedIndex = 0;
final List<Widget> _pages = [
HomePage(),
SearchPage(),
ProfilePage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Navigation Example'),
),
body: _pages[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
),
],
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
),
);
}
}
Когда использовать Scaffold
✅ Используй Scaffold когда:
- Нужна стандартная Material Design структура
- Нужна AppBar с заголовком
- Нужна навигация (Drawer, BottomNavigationBar)
- Нужно отобразить SnackBar или Dialog
- Нужна FloatingActionButton
// Scaffold автоматически:
// - Добавляет padding под AppBar
// - Добавляет padding под BottomNavigationBar
// - Позиционирует FloatingActionButton
// - Показывает SnackBar с правильной позицией
❌ НЕ используй Scaffold когда:
- Создаешь кастомный дизайн (не Material Design)
- Работаешь с Cupertino (iOS) стилем
- Нужна полная кастомизация макета
- Создаешь component library
Практические советы
1. Используй resizeToAvoidBottomInset для клавиатуры
Scaffold(
resizeToAvoidBottomInset: true, // По умолчанию true
body: SingleChildScrollView(
child: Column(
children: [
TextField(), // Не будет скрыта клавиатурой
],
),
),
)
2. FloatingActionButton лучше делать в одного экрана
// ❌ Плохо: FloatingActionButton на каждый экран
if (_selectedIndex == 0) {
floatingActionButton: FloatingActionButton(...);
}
// ✅ Хорошо: FAB только где нужен
floatingActionButton: _selectedIndex == 0
? FloatingActionButton(...)
: null,
3. Используй SafeArea для notch'ей и bottom insets
Scaffold(
body: SafeArea(
child: Text('Safe from notches'),
),
// Или используй viewInsets и viewPadding
)
Когда НЕ использовать Scaffold
Пример: Чистый страничный экран
// ❌ Неправильно
Scaffold(
appBar: SizedBox.shrink(), // Пустая AppBar
body: FullScreenImage(),
)
// ✅ Правильно
Stack(
children: [
FullScreenImage(),
Positioned(
top: 0,
left: 0,
child: BackButton(),
),
],
)
Scaffold — это solid choice для 90% Material Design экранов. Он обеспечивает правильное поведение, отступы, и интеграцию с Material компонентами. Знание его свойств делает UI разработку в Flutter быстрой и предсказуемой.