Flutter остаётся одной из самых быстрорастущих платформ для кроссплатформенной разработки. По данным Statista на начало 2026 года, более 42% мобильных разработчиков используют Flutter, а количество пакетов на pub.dev превысило 45 000. Однако даже опытные инженеры тратят часы на рутинные задачи: написание boilerplate-кода для state management, настройку анимаций или создание кастомных виджетов. В этой статье я собрал 15 промтов, которые помогут вам ускорить разработку на Flutter. Промты разбиты на три уровня: базовые (для начинающих), продвинутые (для уверенных пользователей) и экспертные (для архитекторов и лидов). Каждый промт сопровождается примером результата и кодом.
Базовые промты: виджеты и интерфейсы
1. Создание кастомного виджета с параметрами
Задача: Сгенерировать виджет с возможностью настройки цвета, размера и текста.
Промт:
Напиши на Dart кастомный StatelessWidget под названием CustomButton, который принимает параметры: String label, Color backgroundColor, double borderRadius. Виджет должен быть кнопкой с закруглёнными углами, а при нажатии выводить snackbar с текстом label.
Пример результата:
import 'package:flutter/material.dart';
class CustomButton extends StatelessWidget {
final String label;
final Color backgroundColor;
final double borderRadius;
const CustomButton({
Key? key,
required this.label,
this.backgroundColor = Colors.blue,
this.borderRadius = 12.0,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(label)),
);
},
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius),
),
),
child: Text(label, style: const TextStyle(color: Colors.white)),
);
}
}
Этот промт идеально подходит для быстрого прототипирования UI. Убедитесь, что используете required для обязательных параметров.
2. Адаптивный GridView
Задача: Создать GridView, который автоматически подстраивается под размер экрана.
Промт:
Создай StatelessWidget AdaptiveGrid, который принимает список виджетов и количество колонок для разных размеров экрана (телефон: 2, планшет: 3, десктоп: 4). Используй LayoutBuilder.
Пример результата:
import 'package:flutter/material.dart';
class AdaptiveGrid extends StatelessWidget {
final List<Widget> children;
const AdaptiveGrid({Key? key, required this.children}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
int crossAxisCount;
if (constraints.maxWidth < 600) {
crossAxisCount = 2;
} else if (constraints.maxWidth < 900) {
crossAxisCount = 3;
} else {
crossAxisCount = 4;
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
childAspectRatio: 1.0,
),
itemCount: children.length,
itemBuilder: (context, index) => children[index],
);
},
);
}
}
Адаптивные сетки — основа современных приложений. Flutter официально рекомендует использовать LayoutBuilder для таких задач (см. документацию Flutter.dev).
3. Кастомный AppBar с поиском
Задача: Написать виджет SearchAppBar с анимированным полем поиска.
Промт:
Создай StatefulWidget SearchAppBar, который при нажатии на иконку поиска расширяет ввод текста с анимацией. Используй AnimatedContainer.
Пример результата:
import 'package:flutter/material.dart';
class SearchAppBar extends StatefulWidget {
@override
_SearchAppBarState createState() => _SearchAppBarState();
}
class _SearchAppBarState extends State<SearchAppBar> {
bool _isSearching = false;
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return AppBar(
title: _isSearching
? TextField(
controller: _controller,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Поиск...',
border: InputBorder.none,
),
)
: const Text('Моё приложение'),
actions: [
IconButton(
icon: AnimatedContainer(
duration: const Duration(milliseconds: 300),
child: Icon(_isSearching ? Icons.close : Icons.search),
),
onPressed: () {
setState(() {
_isSearching = !_isSearching;
});
},
),
],
);
}
}
Этот промт часто используется в коммерческих проектах. Обратите внимание: AnimatedContainer автоматически анимирует переходы свойств.
Продвинутые промты: state management, анимации и работа с данными
4. Основной counter-приложение на Bloc
Задача: Создать простое приложение-счётчик с использованием Bloc.
Промт:
Напиши на Dart Bloc для счётчика: события Increment и Decrement, состояние CounterState с полем count. Подключи BlocProvider в main.dart и BlocBuilder в виджете.
Пример результата (основные файлы):
// counter_bloc.dart
import 'package:flutter_bloc/flutter_bloc.dart';
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0) {
on<Increment>((event, emit) => emit(state + 1));
on<Decrement>((event, emit) => emit(state - 1));
}
}
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
// main.dart
void main() {
runApp(
BlocProvider(
create: (context) => CounterBloc(),
child: MyApp(),
),
);
}
Полный код включает виджет с BlocBuilder. Bloc — один из самых популярных паттернов state management, используемый в продакшене (например, в приложении Google Pay).
5. Управление состоянием с Riverpod
Задача: Создать провайдера для списка задач и виджет для отображения.
Промт:
Используя Riverpod, создай StateNotifierProvider для списка задач (модель Task с полями id, title, isDone). Реализуй функции addTask и toggleTask. Напиши виджет, который отображает список и позволяет добавлять задачи.
Пример результата:
import 'package:flutter_riverpod/flutter_riverpod.dart';
class Task {
final int id;
final String title;
final bool isDone;
Task({required this.id, required this.title, this.isDone = false});
}
class TaskNotifier extends StateNotifier<List<Task>> {
TaskNotifier() : super([]);
void addTask(String title) {
state = [...state, Task(id: state.length + 1, title: title)];
}
void toggleTask(int id) {
state = state.map((task) {
return task.id == id ? Task(id: task.id, title: task.title, isDone: !task.isDone) : task;
}).toList();
}
}
final taskProvider = StateNotifierProvider<TaskNotifier, List<Task>>((ref) => TaskNotifier());
Riverpod — это современная альтернатива Bloc, которая устраняет необходимость в BuildContext при чтении состояния. По данным опроса Flutter Community 2025, Riverpod используют 28% разработчиков.
6. Анимация перехода между экранами
Задача: Создать кастомную анимацию для Navigator.push.
Промт:
Напиши класс CustomRoute с использованием PageRouteBuilder. Анимация: новый экран выезжает снизу вверх с эффектом пружины (spring).
Пример результата:
import 'package:flutter/material.dart';
class CustomRoute extends PageRouteBuilder {
final Widget page;
CustomRoute({required this.page})
: super(
pageBuilder: (context, animation, secondaryAnimation) => page,
transitionsBuilder: (context, animation, secondaryAnimation, child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation,
curve: Curves.elasticOut,
)),
child: child,
);
},
);
}
Используйте Navigator.push(context, CustomRoute(page: NewScreen())). Эффект пружины (elasticOut) добавляет приятную физичность, что подтверждается исследованиями Material Design.
7. Работа с HTTP-запросами и кэшированием
Задача: Написать сервис для получения данных с API с кэшированием.
Промт:
Создай класс ApiService с методом fetchUsers, который делает GET-запрос к https://jsonplaceholder.typicode.com/users. Реализуй кэширование с помощью пакета dio и shared_preferences.
Пример результата:
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ApiService {
final Dio _dio = Dio();
Future<List<dynamic>> fetchUsers() async {
final prefs = await SharedPreferences.getInstance();
final cached = prefs.getString('users');
if (cached != null) {
return List<dynamic>.from(cached as List);
}
final response = await _dio.get('https://jsonplaceholder.typicode.com/users');
if (response.statusCode == 200) {
await prefs.setString('users', response.data.toString());
return response.data;
}
throw Exception('Failed to load users');
}
}
Обратите внимание: для продакшена используйте dio с интерцепторами для логирования. SharedPreferences подходит для простого кэширования, но для больших данных лучше hive или sqflite.
8. Анимация списка с StaggeredAnimations
Задача: Реализовать анимацию появления элементов списка с задержкой.
Промт:
Напиши виджет AnimatedListView, который анимирует появление каждого элемента с задержкой 100 мс. Используй AnimationController и StaggeredAnimation.
Пример результата:
import 'package:flutter/material.dart';
class AnimatedListView extends StatefulWidget {
final List<Widget> children;
const AnimatedListView({Key? key, required this.children}) : super(key: key);
@override
_AnimatedListViewState createState() => _AnimatedListViewState();
}
class _AnimatedListViewState extends State<AnimatedListView>
with TickerProviderStateMixin {
late List<AnimationController> _controllers;
@override
void initState() {
super.initState();
_controllers = List.generate(widget.children.length, (index) {
return AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
)..forward();
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: widget.children.length,
itemBuilder: (context, index) {
return AnimatedBuilder(
animation: _controllers[index],
builder: (context, child) {
return Opacity(
opacity: _controllers[index].value,
child: Transform.translate(
offset: Offset(0, 50 * (1 - _controllers[index].value)),
child: child,
),
);
},
child: widget.children[index],
);
},
);
}
@override
void dispose() {
for (var controller in _controllers) {
controller.dispose();
}
super.dispose();
}
}
В реальных проектах такую анимацию можно встретить в лентах новостей. Убедитесь, что контроллеры корректно удаляются в dispose.
Экспертные промты: архитектура, тестирование и производительность
9. Чистая архитектура с Repository и UseCases
Задача: Спроектировать модуль для аутентификации по Clean Architecture.
Промт:
Напиши структуру папок и классы для модуля аутентификации: AuthRepository (абстракция), AuthRepositoryImpl, LoginUseCase, RegisterUseCase. Используй либо либо Result-класс для обработки ошибок. Покажи пример использования в Bloc.
Пример результата (структура):
lib/
features/
auth/
data/
repositories/
auth_repository_impl.dart
datasources/
auth_remote_datasource.dart
domain/
repositories/
auth_repository.dart
usecases/
login_usecase.dart
presentation/
bloc/
auth_bloc.dart
Этот подход рекомендован в книге "Clean Architecture" Роберта Мартина и активно применяется в крупных проектах Flutter (например, в приложении BMW).
10. Оптимизация производительности с RepaintBoundary
Задача: Оптимизировать анимацию множества виджетов.
Промт:
Создай виджет PerformanceList, который отображает 1000 элементов с анимацией и использует RepaintBoundary для каждого элемента. Объясни, почему это улучшает производительность.
Пример результата:
import 'package:flutter/material.dart';
class PerformanceList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 1000,
itemBuilder: (context, index) {
return RepaintBoundary(
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: ListTile(
title: Text('Элемент $index'),
),
),
);
},
);
}
}
RepaintBoundary изолирует область перерисовки, что предотвращает перерисовку всего дерева при анимации одного элемента. Это критично для приложений с большими списками (например, лента Instagram).
11. Тестирование с Mockito и bloc_test
Задача: Написать юнит-тесты для Bloc с использованием mockito.
Промт:
Напиши тесты для CounterBloc: проверь, что при событии Increment состояние увеличивается на 1, а при Decrement уменьшается. Используй bloc_test и mockito для мокирования репозитория.
Пример результата:
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('CounterBloc', () {
blocTest<CounterBloc, int>(
'emits [1] when Increment is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Increment()),
expect: () => [1],
);
blocTest<CounterBloc, int>(
'emits [-1] when Decrement is added',
build: () => CounterBloc(),
act: (bloc) => bloc.add(Decrement()),
expect: () => [-1],
);
});
}
Тестирование — обязательная часть CI/CD. Согласно отчёту Google 2024, приложения с тестовым покрытием более 80% имеют на 50% меньше багов в продакшене.
12. Интеграция с нативным кодом через MethodChannel
Задача: Вызвать нативный метод iOS/Android из Dart.
Промт:
Напиши класс NativeBridge, который вызывает метод getBatteryLevel через MethodChannel. Покажи реализацию на Swift и Kotlin.
Пример результата (Dart-часть):
import 'package:flutter/services.dart';
class NativeBridge {
static const platform = MethodChannel('com.example/battery');
Future<String> getBatteryLevel() async {
try {
final result = await platform.invokeMethod('getBatteryLevel');
return result;
} on PlatformException catch (e) {
return 'Ошибка: ${e.message}';
}
}
}
MethodChannel — стандартный способ интеграции. Однако для новых проектов Flutter рекомендует использовать Pigeon для генерации типобезопасного кода.
13. Работа с Isolates для тяжёлых вычислений
Задача: Выполнить обработку большого JSON в фоновом потоке.
Промт:
Создай функцию parseLargeJson, которая использует Isolate для парсинга JSON-строки размером 10 МБ. Верни результат в основной поток через SendPort.
Пример результата:
import 'dart:convert';
import 'dart:isolate';
Future<Map<String, dynamic>> parseLargeJson(String jsonString) async {
final receivePort = ReceivePort();
await Isolate.spawn((sendPort) {
final result = jsonDecode(jsonString);
sendPort.send(result);
}, receivePort.sendPort);
return await receivePort.first as Map<String, dynamic>;
}
Isolates позволяют не блокировать UI. Этот приём используется в приложениях для анализа данных, например, в трекерах финансов.
14. Кастомный рендеринг с CustomPainter
Задача: Нарисовать анимированный график.
Промт:
Напиши класс LineChartPainter, который рисует линию по точкам с анимацией. Использует AnimationController для плавного появления линии.
Пример результата:
import 'package:flutter/material.dart';
class LineChartPainter extends CustomPainter {
final List<double> data;
final double progress; // от 0 до 1
LineChartPainter({required this.data, required this.progress});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
final path = Path();
for (int i = 0; i < data.length * progress; i++) {
final x = i * size.width / data.length;
final y = (1 - data[i] / 100) * size.height;
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant LineChartPainter oldDelegate) {
return oldDelegate.progress != progress;
}
}
CustomPainter даёт полный контроль над рендерингом. В продакшене его используют для чартов, канвасов и игр.
15. Архитектура с Dependency Injection (GetIt)
Задача: Настроить DI для проекта с GetIt.
Промт:
Создай файл injection_container.dart, который регистрирует синглтоны для ApiService, AuthRepository и CounterBloc. Покажи, как использовать в виджете.
Пример результата:
import 'package:get_it/get_it.dart';
final sl = GetIt.instance;
void initDependencies() {
sl.registerLazySingleton<ApiService>(() => ApiService());
sl.registerLazySingleton<AuthRepository>(() => AuthRepositoryImpl());
sl.registerFactory<CounterBloc>(() => CounterBloc());
}
// В виджете:
final counterBloc = sl<CounterBloc>();
GetIt — самый популярный DI-контейнер во Flutter, но для тестов лучше использовать Injectable с кодогенерацией.
Заключение
Мы разобрали 15 промтов, покрывающих ключевые аспекты Flutter-разработки: от простых виджетов до сложной архитектуры и оптимизации. Каждый промт — это не просто шаблон, а готовый кирпичик для вашего приложения. Помните: промты — это инструмент, а не замена пониманию. Всегда адаптируйте их под свои задачи и следите за актуальностью используемых пакетов. Например, если вы используете Bloc, версия 8.0 уже устарела — переходите на Bloc 9.0. А для тестирования обязательно используйте mockito 5.6 или выше. Надеюсь, эта подборка сэкономит вам часы гугления и поможет сосредоточиться на действительно важных вещах — создании классных приложений.
Комментарии