15 промтов для Flutter: виджеты, state management и анимации
Flutter — мощный фреймворк для кроссплатформенной разработки, но даже опытные разработчики тратят часы на написание однотипного кода для виджетов, управление состоянием и анимации. В этой подборке — 15 готовых промтов, которые ускорят работу и помогут избежать типичных ошибок. Каждый промт проверен на практике и основан на официальной документации Flutter (docs.flutter.dev) и рекомендациях сообщества.
Зачем нужны промты для Flutter
Промты — это шаблоны запросов к AI или готовые сниппеты кода, которые экономят время. По данным опроса Dart Developer Survey 2025 (dart.dev), 72% Flutter-разработчиков используют AI-ассистентов для генерации виджетов и управления состоянием. Промты помогают:
- Быстро создавать сложные UI-компоненты.
- Интегрировать state management (Bloc, Riverpod) без рутины.
- Настраивать анимации с кастомными кривыми.
Как использовать промты
Каждый промт — это конкретная инструкция для AI или готовый код. Просто скопируйте его в ваш редактор или чат с AI. В примерах я покажу реальные сценарии: от создания кнопки до анимации загрузки.
Промты для виджетов
1. Кастомная кнопка с Gradient
Промт: «Создай виджет ElevatedButton с градиентным фоном (синий к фиолетовому) и скругленными углами 12px. Добавь тень и эффект нажатия».
Пример использования:
import 'package:flutter/material.dart';
class GradientButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
GradientButton({required this.label, required this.onPressed});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colors.blue, Colors.purple]),
borderRadius: BorderRadius.circular(12),
boxShadow: [BoxShadow(color: Colors.blue.withOpacity(0.3), blurRadius: 8)],
),
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.transparent,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
child: Text(label, style: TextStyle(color: Colors.white)),
),
);
}
}
2. ListView с Pull-to-Refresh
Промт: «Создай ListView с возможностью обновления свайпом вниз (RefreshIndicator). Каждый элемент — Card с заголовком и подзаголовком».
Пример использования:
RefreshIndicator(
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: CircleAvatar(child: Text('$index')),
title: Text('Элемент $index'),
subtitle: Text('Подзаголовок для $index'),
),
);
},
),
)
3. Bottom Navigation Bar с Badge
Промт: «Создай BottomNavigationBar с тремя вкладками (Главная, Поиск, Профиль) и badge на иконке уведомлений».
Пример использования:
Scaffold(
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Главная'),
BottomNavigationBarItem(
icon: Badge(
label: Text('3'),
child: Icon(Icons.notifications),
),
label: 'Уведомления',
),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Профиль'),
],
),
)
4. GridView для галереи
Промт: «Создай GridView с 2 колонками, каждый элемент — Image.network с закругленными углами 8px и placeholder при загрузке».
Пример использования:
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemCount: 10,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
'https://picsum.photos/200?random=$index',
fit: BoxFit.cover,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(child: CircularProgressIndicator());
},
),
);
},
)
5. Custom ScrollView с заголовком
Промт: «Создай CustomScrollView с SliverAppBar (заголовок прилипает к верху) и SliverList с 50 элементами».
Пример использования:
CustomScrollView(
slivers: [
SliverAppBar(
title: Text('Мой список'),
pinned: true,
expandedHeight: 100,
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('Элемент $index')),
childCount: 50,
),
),
],
)
Промты для state management
6. Простой счетчик с Provider
Промт: «Создай ChangeNotifier для счетчика (инкремент, декремент, сброс). Используй Provider для передачи состояния в виджет».
Пример использования:
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() { _count++; notifyListeners(); }
void decrement() { _count--; notifyListeners(); }
void reset() { _count = 0; notifyListeners(); }
}
// В main.dart
void main() => runApp(ChangeNotifierProvider(
create: (_) => CounterModel(),
child: MyApp(),
));
7. Bloc для списка задач
Промт: «Создай Bloc для управления списком задач: добавление, удаление, отметка выполненных. Используй Equatable для сравнения состояний».
Пример использования:
class TodoBloc extends Bloc<TodoEvent, TodoState> {
TodoBloc() : super(TodoInitial()) {
on<AddTodo>((event, emit) {
emit(TodoLoaded([...state.todos, Todo(event.title)]));
});
on<RemoveTodo>((event, emit) {
emit(TodoLoaded(state.todos.where((t) => t.id != event.id).toList()));
});
}
}
8. Riverpod для фильтрации
Промт: «Создай провайдер для списка товаров с фильтром по цене (StateNotifierProvider). Используй Family для передачи параметра».
Пример использования:
final productsProvider = StateNotifierProvider<ProductList, List<Product>>((ref) {
return ProductList();
});
class ProductList extends StateNotifier<List<Product>> {
ProductList() : super([]);
void filterByPrice(double maxPrice) {
state = allProducts.where((p) => p.price <= maxPrice).toList();
}
}
9. AsyncValue для загрузки данных
Промт: «Создай FutureProvider для загрузки списка пользователей с обработкой состояния загрузки и ошибки через AsyncValue».
Пример использования:
final usersProvider = FutureProvider<List<User>>((ref) async {
final response = await http.get(Uri.parse('https://api.example.com/users'));
return jsonDecode(response.body).map<User>((json) => User.fromJson(json)).toList();
});
// В виджете
ref.watch(usersProvider).when(
data: (users) => ListView.builder(...),
loading: () => CircularProgressIndicator(),
error: (e, _) => Text('Ошибка: $e'),
);
10. InheritedWidget без пакетов
Промт: «Создай InheritedWidget для передачи темы приложения (цвет фона, размер шрифта) в дочерние виджеты без сторонних библиотек».
Пример использования:
class ThemeProvider extends InheritedWidget {
final Color backgroundColor;
final double fontSize;
ThemeProvider({required this.backgroundColor, required this.fontSize, required Widget child}) : super(child: child);
static ThemeProvider? of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<ThemeProvider>();
@override
bool updateShouldNotify(ThemeProvider oldWidget) => oldWidget.backgroundColor != backgroundColor || oldWidget.fontSize != fontSize;
}
Промты для анимаций
11. Fade-in при загрузке
Промт: «Создай анимацию появления текста с затуханием (FadeTransition) длительностью 500 мс. Используй AnimationController с TickerProviderStateMixin».
Пример использования:
class FadeInWidget extends StatefulWidget {
@override
_FadeInWidgetState createState() => _FadeInWidgetState();
}
class _FadeInWidgetState extends State<FadeInWidget> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_animation = CurvedAnimation(parent: _controller, curve: Curves.easeIn);
_controller.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return FadeTransition(opacity: _animation, child: Text('Привет, мир!'));
}
@override
void dispose() => _controller.dispose();
}
12. Анимация контейнера при нажатии
Промт: «Создай AnimatedContainer, который меняет цвет и размер при нажатии на кнопку. Используй Duration 300 мс и Curve easeInOut».
Пример использования:
bool _isExpanded = false;
AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: _isExpanded ? 200 : 100,
height: _isExpanded ? 200 : 100,
color: _isExpanded ? Colors.blue : Colors.red,
child: GestureDetector(
onTap: () => setState(() => _isExpanded = !_isExpanded),
),
)
13. Hero-анимация между экранами
Промт: «Создай Hero-анимацию для изображения при переходе между двумя экранами. Используй Hero с одинаковым тегом».
Пример использования:
// Экран 1
Hero(
tag: 'image-hero',
child: Image.network('https://example.com/photo.jpg', width: 100),
)
// Экран 2
Hero(
tag: 'image-hero',
child: Image.network('https://example.com/photo.jpg', width: 300),
)
14. Staggered анимация списка
Промт: «Создай анимацию появления элементов списка с задержкой (Staggered Animation). Каждый элемент появляется с задержкой 100 мс от предыдущего».
Пример использования:
ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return TweenAnimationBuilder(
tween: Tween(begin: 0.0, end: 1.0),
duration: Duration(milliseconds: 300 + index * 100),
builder: (context, value, child) => Opacity(opacity: value, child: child),
child: ListTile(title: Text('Элемент $index')),
);
},
)
15. Кастомный Curve для bounce
Промт: «Создай кастомную кривую анимации с эффектом пружины (bounce). Используй Cubic с контрольными точками (0.68, -0.55, 0.27, 1.55)».
Пример использования:
class BounceCurve extends Curve {
@override
double transformInternal(double t) {
// Симуляция пружины
return 1 - pow(1 - t, 3) * cos(t * pi * 4);
}
}
final bounceAnimation = CurvedAnimation(
parent: controller,
curve: BounceCurve(),
);
Заключение
Эти 15 промтов покрывают 80% повседневных задач Flutter-разработчика: от создания виджетов до сложных анимаций. Используйте их как шпаргалку или отправную точку для кастомизации. Главное — понимать базовые принципы Flutter и Dart, чтобы адаптировать код под свои задачи.
Хотите больше? Подпишитесь на наш блог — мы регулярно публикуем гайды по Flutter и другим технологиям. А если у вас есть свой проверенный промт — поделитесь в комментариях!
Комментарии