Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Где и как применяется виджет Expanded в Flutter
Expanded — это виджет в Flutter, который заставляет дочерний элемент занимать всё доступное пространство в родительском Row или Column.
Основное использование
// Базовое использование Expanded
Row(
children: [
Container(width: 100, height: 50, color: Colors.red),
Expanded(
child: Container(color: Colors.green), // Займёт всё оставшееся место
),
Container(width: 100, height: 50, color: Colors.blue),
],
)
// Результат: красный(100) + зелёный(всё оставшееся) + синий(100)
Как это работает:
- В контексте Row/Column — Expanded растягивает виджет на всё доступное пространство
- Параметр flex — определяет, сколько доли пространства займёт виджет
- Обязателен Row или Column — вне этих контейнеров Expanded не работает
Параметр flex (пропорции)
// flex определяет соотношение размеров
Row(
children: [
Expanded(
flex: 1, // Займёт 1/4 пространства
child: Container(color: Colors.red),
),
Expanded(
flex: 2, // Займёт 2/4 пространства (в два раза больше)
child: Container(color: Colors.green),
),
Expanded(
flex: 1, // Займёт 1/4 пространства
child: Container(color: Colors.blue),
),
],
)
// Пропорции: красный 25% + зелёный 50% + синий 25%
Практические примеры использования
1. Раскладка кнопок в строку:
// Кнопки одинакового размера, распределённые по ширине
Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {},
child: Text('Cancel'),
),
),
SizedBox(width: 16), // Промежуток
Expanded(
child: ElevatedButton(
onPressed: () {},
child: Text('OK'),
),
),
],
)
2. Форма с полями ввода:
// Поле ввода занимает всё оставшееся место
Row(
children: [
Text('Email: '),
Expanded(
child: TextField(
decoration: InputDecoration(
hintText: 'Enter email',
border: OutlineInputBorder(),
),
),
),
],
)
3. Список с элементами разных размеров:
ListTile(
leading: CircleAvatar(child: Text('A')),
title: Text('Alice'),
subtitle: Text('Active 5 minutes ago'),
trailing: Icon(Icons.more_vert),
)
// Или вручную:
Row(
children: [
CircleAvatar(child: Text('A')),
SizedBox(width: 16),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Alice'),
Text('Active 5 minutes ago', style: TextStyle(fontSize: 12)),
],
),
),
Icon(Icons.more_vert),
],
)
4. Header с логотипом и меню:
Row(
children: [
Image.asset('logo.png', width: 50, height: 50),
SizedBox(width: 16),
Expanded(
child: Text(
'My App',
style: Theme.of(context).textTheme.headlineSmall,
),
),
IconButton(icon: Icon(Icons.menu), onPressed: () {}),
],
)
5. Card с содержимым и действиями:
Card(
child: Column(
children: [
Row(
children: [
Image.network('image.jpg', width: 80, height: 80),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Product Name'),
Text('Price: \$99.99'),
SizedBox(height: 8),
ElevatedButton(
onPressed: () {},
child: Text('Add to Cart'),
),
],
),
),
],
),
],
),
)
Expanded vs другие виджеты
Expanded vs Flexible:
// Expanded - всегда занимает максимум доступного пространства
Row(
children: [
Expanded(
child: Text('This will be stretched'),
),
],
)
// Flexible - может занять меньше, если дочерний виджет меньше
Row(
children: [
Flexible(
child: Text('This might not be stretched'),
),
],
)
Expanded vs SizedBox:
// Expanded - занимает всё доступное место
// Хорошо, когда размер заранее неизвестен
Row(
children: [
Expanded(
child: Container(color: Colors.red),
),
],
)
// SizedBox - фиксированный размер
// Хорошо, когда размер известен
Row(
children: [
SizedBox(
width: 100,
child: Container(color: Colors.red),
),
],
)
Ошибки при использовании Expanded
Ошибка 1: Expanded вне Row/Column
// ОШИБКА - Expanded не может быть здесь
Scaffold(
body: Expanded(
child: Text('Error'),
),
)
// ПРАВИЛЬНО - используй Expanded в Row/Column
Scaffold(
body: Row(
children: [
Expanded(
child: Text('OK'),
),
],
),
)
Ошибка 2: Nested Expanded без правильной конфигурации
// Может быть проблема
Column(
children: [
Expanded(
child: Row(
children: [
Expanded(
child: Text('A'),
),
Expanded(
child: Text('B'),
),
],
),
),
],
)
// Лучше явно указать mainAxisSize
Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(child: Text('A')),
Expanded(child: Text('B')),
],
),
),
],
)
Примеры из реальных приложений
Профиль пользователя:
Widget buildUserProfile() {
return Column(
children: [
Container(
color: Colors.blue,
height: 200,
child: Center(
child: CircleAvatar(radius: 50),
),
),
SizedBox(height: 16),
Row(
children: [
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('John Doe', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Text('john@example.com'),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
child: Text('Follow'),
),
],
),
),
Icon(Icons.more_vert),
SizedBox(width: 16),
],
),
],
);
}
Chat bubble:
Widget buildChatBubble(String message, bool isMe) {
return Row(
mainAxisAlignment: isMe ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
if (!isMe) SizedBox(width: 8),
Expanded(
child: Container(
margin: EdgeInsets.all(8),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: isMe ? Colors.blue : Colors.grey,
borderRadius: BorderRadius.circular(12),
),
child: Text(
message,
style: TextStyle(color: Colors.white),
),
),
),
if (isMe) SizedBox(width: 8),
],
);
}
Когда НЕ использовать Expanded
- Когда размер известен — используй SizedBox с явным размером
- Для центрирования — используй Center или MainAxisAlignment
- Вне Row/Column — используй FractionallySizedBox или MediaQuery
- Для padding/margin — используй Padding и Margin вместо Expanded
Expanded — это незаменимый виджет для создания адаптивных интерфейсов, которые правильно распределяют пространство между элементами.