15 промтов для Flutter: от виджетов до Bloc и анимаций — подборка для разработчиков

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 или выше. Надеюсь, эта подборка сэкономит вам часы гугления и поможет сосредоточиться на действительно важных вещах — создании классных приложений.

← Все статьи

Комментарии

Читайте также

Как подключить AI-агента ASI Biont к Salesforce Commerce Cloud: автоматизация без кода для электронной коммерции

12 июля 2026

15 промтов для Excel и Google Sheets: от формул до дашбордов — полный гайд 2026

12 июля 2026

От необработанных данных к умным решениям: как подключить устройства Modbus/TCP к промышленному ИИ-агенту без программирования

12 июля 2026

Природа как сервис: что заменит телевизоры в премиальных домах

12 июля 2026

7 промтов для работы с LLM: fine-tuning, RAG и промпт-инжиниринг в 2026 году

12 июля 2026

Автоматизация анализа трафика с помощью интеграции Яндекс.Метрики: ИИ-агент экономит 30% ручного труда

12 июля 2026

Прокси-роутинг для веб-скрапинга и Vibe Scraping в 2026: лучшие прокси для сбора данных (и почему ваш текущий прокси не выдержит прода)

12 июля 2026

7 промтов для CI/CD: GitHub Actions, GitLab CI и ArgoCD — шпаргалка для DevOps

12 июля 2026

Cloudflare стал из «трубы» вахтёром и кассиром Интернета: как CDN-гигант превратился в главного контролёра трафика

12 июля 2026