← Назад к вопросам
Что такое BuildContext и как он используется?
2.2 Middle🔥 151 комментариев
#Flutter виджеты
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое BuildContext и как он используется
BuildContext — это объект, который представляет позицию виджета в дереве элементов (Element Tree). Это фундаментальное понятие в Flutter, которое позволяет виджетам взаимодействовать со своим окружением и получать данные от предков в дереве виджетов.
Что это такое?
// BuildContext это по сути ссылка на Element
Widget build(BuildContext context) {
// context — это ссылка на Element этого виджета
// через context мы можем:
// 1. Получать данные от предков (Theme, MediaQuery, Inherited)
// 2. Выполнять навигацию
// 3. Показывать диалоги, снекбары
// 4. Получать информацию о размере экрана
}
Архитектура
Widget (конфигурация) — неизменяемая
↓
Element (состояние, позиция в дереве) — это BuildContext
↓
RenderObject (отрисовка)
BuildContext — это объект Element, который связывает виджет с его позицией в дереве.
Основные способы использования
1. Получение Theme
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Получить Theme
final theme = Theme.of(context);
final primaryColor = theme.primaryColor;
final textTheme = theme.textTheme;
return Container(
color: theme.colorScheme.surface,
child: Text(
'Hello',
style: theme.textTheme.titleLarge,
),
);
}
}
2. Получение информации о размере экрана
class ResponsiveWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
final screenWidth = mediaQuery.size.width;
final screenHeight = mediaQuery.size.height;
final isPortrait = mediaQuery.orientation == Orientation.portrait;
final devicePixelRatio = mediaQuery.devicePixelRatio;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Width: ${screenWidth.toStringAsFixed(0)}'),
Text('Height: ${screenHeight.toStringAsFixed(0)}'),
Text('Orientation: ${isPortrait ? "Portrait" : "Landscape"}'),
if (screenWidth > 600)
Text('Large screen')
else
Text('Small screen'),
],
),
);
}
}
3. Навигация между экранами
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
// Используем context для навигации
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondScreen(),
),
);
},
child: Text('Go to Second Screen'),
),
),
);
}
}
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
// Назад
Navigator.of(context).pop();
},
child: Text('Go Back'),
),
),
);
}
}
4. Показание диалогов и снекбаров
class DialogExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
// Показать AlertDialog
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
title: Text('Confirm'),
content: Text('Are you sure?'),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(),
child: Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: Text('OK'),
),
],
),
);
},
child: Text('Show Dialog'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Показать Snackbar
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Hello from Snackbar!'),
duration: Duration(seconds: 2),
),
);
},
child: Text('Show Snackbar'),
),
],
),
),
);
}
}
5. Работа с FocusScope
class FormExample extends StatefulWidget {
@override
State<FormExample> createState() => _FormExampleState();
}
class _FormExampleState extends State<FormExample> {
late FocusNode emailFocus;
late FocusNode passwordFocus;
@override
void initState() {
super.initState();
emailFocus = FocusNode();
passwordFocus = FocusNode();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
TextField(
focusNode: emailFocus,
decoration: InputDecoration(labelText: 'Email'),
onSubmitted: (_) {
// Перейти на следующее поле
FocusScope.of(context).requestFocus(passwordFocus);
},
),
TextField(
focusNode: passwordFocus,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
onSubmitted: (_) {
// Убрать фокус с клавиатуры
FocusScope.of(context).unfocus();
},
),
],
),
),
);
}
@override
void dispose() {
emailFocus.dispose();
passwordFocus.dispose();
super.dispose();
}
}
Inherited Widgets с BuildContext
// Создание собственного Inherited Widget
class ThemeProvider extends InheritedWidget {
final String themeName;
ThemeProvider({
required this.themeName,
required Widget child,
}) : super(child: child);
static ThemeProvider of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<ThemeProvider>()!;
}
@override
bool updateShouldNotify(ThemeProvider oldWidget) {
return themeName != oldWidget.themeName;
}
}
// Использование в дереве
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThemeProvider(
themeName: 'dark',
child: MyHomePage(),
);
}
}
// Получение значения
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = ThemeProvider.of(context);
return Text('Current theme: ${provider.themeName}');
}
}
Практический пример: полная форма
class LoginForm extends StatefulWidget {
@override
State<LoginForm> createState() => _LoginFormState();
}
class _LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
String email = '';
String password = '';
bool isLoading = false;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size; // получить размер экрана
final theme = Theme.of(context); // получить тему
return Scaffold(
appBar: AppBar(title: Text('Login')),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (value) => value?.isEmpty ?? true ? 'Email required' : null,
onChanged: (value) => email = value,
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) => value?.isEmpty ?? true ? 'Password required' : null,
onChanged: (value) => password = value,
),
SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: isLoading ? null : () => _login(context),
child: isLoading
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Text('Login'),
),
),
],
),
),
),
),
);
}
Future<void> _login(BuildContext context) async {
if (!_formKey.currentState!.validate()) return;
setState(() => isLoading = true);
try {
// API call
await Future.delayed(Duration(seconds: 2));
// Навигация
Navigator.of(context).pushReplacementNamed('/home');
} catch (e) {
// Снекбар с ошибкой
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
} finally {
setState(() => isLoading = false);
}
}
}
Важные моменты
1. BuildContext специфичен для каждого виджета
// context это Context ЭТОГО виджета
Widget build(BuildContext context) {
return MyChild(); // MyChild имеет свой context
}
// Нельзя использовать context родителя для MyChild
class MyChild extends StatelessWidget {
@override
Widget build(BuildContext context) {
// это context MyChild, не родителя
}
}
2. BuildContext не рекомендуется передавать в обработчики
// ❌ Плохо
ElevatedButton(
onPressed: () => handleClick(context),
child: Text('Click'),
)
// ✅ Хорошо
ElevatedButton(
onPressed: () {
Navigator.of(context).push(...); // используй context сразу
},
child: Text('Click'),
)
3. Проверка наличия предка
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Проверить наличие предка
final scaffold = ScaffoldMessenger.maybeOf(context);
if (scaffold == null) {
return Text('No Scaffold ancestor');
}
return ElevatedButton(
onPressed: () {
scaffold.showSnackBar(
SnackBar(content: Text('Hello')),
);
},
child: Text('Show Snackbar'),
);
}
}
Вывод: BuildContext — это ключ к взаимодействию виджета со своим окружением в дереве. Через него мы получаем темы, размеры экрана, выполняем навигацию, показываем диалоги и снекбары. Это одно из самых важных понятий в Flutter, которое используется повсеместно.