← Назад к вопросам
Какие типы Keys существуют во Flutter и когда их использовать?
1.8 Middle🔥 222 комментариев
#Flutter виджеты
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Keys в Flutter: типы и применение
Key — это уникальный идентификатор для элемента в дереве виджетов. Это мощный инструмент для сохранения состояния и управления идентичностью элементов при перестроении.
Почему нужны Keys
Проблема без Keys:
class MyList extends StatefulWidget {
@override
State<MyList> createState() => _MyListState();
}
class _MyListState extends State<MyList> {
List<Color> colors = [Colors.red, Colors.green, Colors.blue];
@override
Widget build(BuildContext context) {
return Column(
children: [
// Виджет 1
ColorBox(color: colors[0]),
// Виджет 2
ColorBox(color: colors[1]),
// Виджет 3
ColorBox(color: colors[2]),
ElevatedButton(
onPressed: () {
setState(() {
colors.removeAt(0); // Удаляем первый элемент
// БЕЗ Keys: Flutter может спутать элементы!
// Состояние ColorBox может остаться с неправильным цветом
});
},
child: Text('Remove first'),
),
],
);
}
}
Типы Keys
1. ValueKey — самый распространённый
Использует значение (обычно ID) для идентификации:
class MyList extends StatefulWidget {
@override
State<MyList> createState() => _MyListState();
}
class _MyListState extends State<MyList> {
List<Item> items = [
Item(id: '1', name: 'Item 1'),
Item(id: '2', name: 'Item 2'),
Item(id: '3', name: 'Item 3'),
];
@override
Widget build(BuildContext context) {
return Column(
children: [
...items.map((item) => ItemWidget(
key: ValueKey(item.id), // Уникальный ID
item: item,
)),
ElevatedButton(
onPressed: () {
setState(() => items.removeAt(0));
// С ValueKey: Flutter правильно определит, какой элемент удалён
},
child: Text('Remove first'),
),
],
);
}
}
2. ObjectKey — ключ на основе объекта
Использует сам объект как ключ:
class _MyListState extends State<MyList> {
List<Item> items = [];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ItemWidget(
key: ObjectKey(items[index]), // Весь объект как ключ
item: items[index],
);
},
);
}
}
3. UniqueKey — уникальный ключ
Создаёт уникальный ключ каждый раз:
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<Widget> items = [
CustomForm(key: UniqueKey()), // Новый ключ при каждом создании
];
void addForm() {
setState(() {
items.add(CustomForm(key: UniqueKey()));
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [...items],
);
}
}
4. GlobalKey — глобальный ключ для всего дерева
Позволяет обращаться к State из других мест:
class MyForm extends StatefulWidget {
const MyForm({Key? key}) : super(key: key);
@override
State<MyForm> createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
void submitForm() {
// Валидируем форму из другого места
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (value) {
if (value!.isEmpty) return 'Required';
return null;
},
),
ElevatedButton(
onPressed: submitForm,
child: Text('Submit'),
),
],
),
);
}
}
5. PageStorageKey — сохранение состояния при навигации
class MyList extends StatefulWidget {
@override
State<MyList> createState() => _MyListState();
}
class _MyListState extends State<MyList> {
late ScrollController _scrollController;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
}
@override
Widget build(BuildContext context) {
return ListView.builder(
key: PageStorageKey<String>('my-list'), // Сохраняет позицию скролла
controller: _scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
);
}
}
Сравнение Keys
| Key тип | Использование | Производительность | Популярность |
|---|---|---|---|
| ValueKey | ID, простые значения | Хорошо | Очень высокая |
| ObjectKey | Целые объекты | Хорошо | Средняя |
| UniqueKey | Каждый раз новый ключ | Плохо (много пересчётов) | Низкая |
| GlobalKey | Доступ к State из других мест | Плохо (дорого) | Средняя |
| PageStorageKey | Сохранение состояния при навигации | Хорошо | Средняя |
Практические примеры
Пример 1: Список с удалением
class TodoList extends StatefulWidget {
@override
State<TodoList> createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
List<Todo> todos = [
Todo(id: 1, title: 'Buy milk'),
Todo(id: 2, title: 'Walk dog'),
Todo(id: 3, title: 'Read book'),
];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
return TodoItem(
key: ValueKey(todo.id), // Сохраняет состояние элемента
todo: todo,
onDelete: () {
setState(() => todos.removeAt(index));
},
);
},
);
}
}
Пример 2: Form с валидацией
class RegistrationForm extends StatefulWidget {
@override
State<RegistrationForm> createState() => _RegistrationFormState();
}
class _RegistrationFormState extends State<RegistrationForm> {
final _formKey = GlobalKey<FormState>();
String email = '';
String password = '';
void _submit() {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// Отправляем данные
print('Email: $email, Password: $password');
}
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
validator: (value) => value!.isEmpty ? 'Email required' : null,
onSaved: (value) => email = value!,
),
TextFormField(
validator: (value) => value!.length < 6 ? 'Min 6 chars' : null,
onSaved: (value) => password = value!,
),
ElevatedButton(
onPressed: _submit,
child: Text('Register'),
),
],
),
);
}
}
Правила использования Keys
Используй ValueKey если:
- Есть уникальный ID для каждого элемента
- Элементы перестраиваются часто
Используй GlobalKey если:
- Нужен доступ к State из других мест
- Работаешь с Form, TextField
Избегай UniqueKey:
- Может вызвать излишние перестроения
- Нарушает оптимизацию Flutter
Keys — это критическая часть Flutter для правильного управления состоянием при динамических списках.