Когда приложение тормозит, первая мысль: «нужно вынести это в отдельный поток». В Flutter эта мысль часто выливается в async/await или Isolate. Но это не взаимозаменяемые вещи, а инструменты для разных задач. И если перепутать, можно получить либо бесполезный код, либо вечно зависающий UI.
Главное заблуждение:
Многие думают: «Раз async/await, значит, не блокирует UI». Но это не так. async/await сам по себе не переносит выполнение в другой поток. Он просто дает удобный способ работать с асинхронными операциями, которые уже неблокирующие по своей природе: запросы к сети, чтение с диска, ожидание таймера. Если внутрь async-функции положить тяжелые вычисления, они будут выполняться в основном потоке и тормозить интерфейс ровно так же, как если бы вы написали их без всяких await.
Когда async/await справляется сам:
Для операций ввода-вывода async/await достаточно. Сеть, базы данных, файловая система - все это уже асинхронно на уровне платформы. Достаточно дождаться результата, и UI останется отзывчивым.
Когда нужно подключать Isolate:
Как только появляются вычисления, которые грузят процессор - парсинг большого JSON, обработка изображений, сложные математические расчеты, - async/await перестает помогать. Здесь нужен настоящий параллелизм. Isolate запускает код в отдельном потоке (или даже ядре) и не трогает основной.
Самый простой способ - compute(). Он берет функцию и данные, запускает их в изоляте и возвращает результат. Идеально для разовых тяжелых задач.
Когда compute не хватает:
Если нужно постоянное взаимодействие с фоновым процессом, например, обработка потока данных или долгая работа с промежуточными результатами - придется использовать Raw Isolate. Там уже ручное управление портами и сообщениями, но зато полный контроль.
Что выбрать:
Async/await и Isolate не конкуренты, а партнеры. Первый отвечает за ожидание, второй - за параллельное выполнение. Смешивать их нужно осознанно, а не по принципу «чтоб не тормозило». Иначе вместо плавного интерфейса получите или вечно грузящийся процессор, или кучу мертвого кода, который ничего не ускоряет.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Всем привет! Команда Flutter опубликовала дорожную карту на 2026 год. Как обычно, без жестких гарантий, но с четкими намерениями. Если коротко: упор на производительность, интеграцию с ИИ и расширение экосистемы. Разбирем главное.
Графика без рывков: Impeller добивает Skia:
На Android завершится переход на Impeller. Для устройств с Android 10 и выше Skia уйдет в прошлое. Это значит конец фризам при первом рендеринге и более предсказуемая производительность. На iOS Impeller уже давно стал стандартом, теперь добираемся до второй платформы.
Для веба ставка делается на WebAssembly. Wasm должен стать стандартом для Flutter Web, приближая производительность к нативному уровню. Если нужно управлять DOM напрямую, предлагают присмотреться к Jaspr - фреймворку на Dart для серверного рендеринга.
GenUI и эфемерный код - Flutter становится ИИ-нативным:
Самая интересная часть - архитектура для агентных интерфейсов. Flutter GenUI SDK позволит создавать UI, который адаптируется к действиям пользователя в реальном времени, генерируясь динамически. Это уже не просто набор экранов, а интерфейсы, которые подстраиваются под контекст.
Чтобы это работало, в Dart планируют добавить поддержку интерпретируемого байт-кода. Это позволит подгружать части приложения по требованию, без публикации в сторах. Фактически - нативный code push, только официальный и встроенный в платформу. Если получится так же гладко, как у Shorebird, но из коробки - будет прорыв.
Full-stack Dart: бэкенд и облако:
Dart пытаются вытащить за пределы клиента. В планах - интеграция с Google Cloud SDK, поддержка Dart в Firebase Cloud Functions и работа с Genkit для ИИ-фич. Звучит амбициозно, но пока выглядит как попытка сделать Dart универсальным языком для всего стека.
ИИ в инструментах - Gemini CLI и Antigravity:
Разработчикам обещают лучшую поддержку Dart и Flutter в ИИ-инструментах от Google. Gemini CLI и новая IDE Antigravity (аналог Cursor) должны глубже понимать код на Dart, а MCP-серверы позволят агентам делать сложные рефакторинги, общаясь напрямую с анализатором.
Дизайн-библиотеки вынесут в независимые пакеты:
Material и Cupertino вынесут в отдельные пакеты. Это ускорит их обновление и снизит связанность с ядром Flutter. Flutter Engine и CLI получат механизмы для расширения, чтобы сторонние платформы (вроде ОС Аврора или Kaspersky OS) могли добавлять поддержку без изменений в основном коде.
Синтаксис и производительность Dart:
В языке появятся приватные именованные параметры, primary constructors и augmentations для генерации кода. build_runner будут улучшать, анализатор - рефакторить для скорости. Работу над компиляцией в Wasm продолжат.
Предсказуемые релизы и работа с сообществом:
Команда пообещала более прозрачный график релизов. По факту они и так выходили каждые три месяца, но теперь это официально зафиксировано. DevRel-ы активизировались, запустили новый образовательный путь для новичков и планируют больше офлайн-ивентов.
2026 год для Flutter сулит завершением больших миграций (Impeller, Wasm) и переходом в новую эру с ИИ-интерфейсами и эфемерным кодом. Dart пытаются сделать полноценным языком для бэкенда, а инструменты разработки более умными и интегрированными с ИИ. Если хотя бы половина этого выстрелит, экосистема ждет серьезный апгрейд.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1🔥1
Когда приложение выходит за пределы пет-проекта, возникает необходимость держать окружения раздельно. Dev, Staging и Production должны жить своей жизнью: с разными API-ключами, бэкендом, а иногда даже иконками и названиями. В Flutter эта задача решается через Flavors. Рассказываю, как настроить и не запутаться.
Что такое Flavors и зачем они нужны:
Flavors (или схемы в iOS, продуктные варианты в Android) позволяют из одной кодовой базы собирать разные варианты приложения. У каждого варианта могут быть свои:
Это дает возможность установить на устройство одновременно dev-версию и продовую, не боясь, что они перезатрут друг друга. И главное - исключает случайную отправку тестового кода в релиз.
Организация кода:
Самый простой способ - сделать отдельные точки входа для каждого окружения. В папке lib создаем файлы:
В каждом передаем в приложение идентификатор среды, чтобы внутри можно было подставлять нужные конфиги.
void main() {
runApp(MyApp(environment: 'DEV'));
}
Android - настройка productFlavors:
В android/app/build.gradle добавляем секцию:
flavorDimensions "default"
productFlavors {
dev {
dimension "default"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
}
staging {
dimension "default"
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
}
production {
dimension "default"
}
}
Это даст разные имена пакетов: .dev, .staging и основное. Приложения не будут конфликтовать при установке.
iOS - схемы и бандлы:
В Xcode нужно продублировать схему Runner для каждого окружения и задать разные идентификаторы бандла в настройках таргета. Например:
В Info.plist можно выставить разные названия приложений, чтобы в меню было видно, какая версия запущена.
Запуск и сборка:
Для запуска нужного flavor используем флаги:
flutter run --flavor dev -t lib/main_dev.dart
flutter build apk --flavor prod -t lib/main_prod.dart
flutter build ios --flavor staging -t lib/main_staging.dart
Управление конфигурацией:
Внутри кода удобно сделать класс с константами для каждого окружения:
class AppConfig {
static const Map<String, String> apiUrls = {
'DEV': 'https://dev.api.example.com',
'STAGING': 'https://staging.api.example.com',
'PROD': 'https://api.example.com',
};
}
А в приложении просто обращаться по ключу, который пришел из main-файла.
Иконки для каждого flavor:
Пакет flutter_launcher_icons умеет генерировать иконки под разные flavors. В pubspec.yaml прописываем:
flutter_launcher_icons:
flavors:
dev:
image_path: "assets/icons/dev_icon.png"
staging:
image_path: "assets/icons/staging_icon.png"
production:
image_path: "assets/icons/prod_icon.png"
Запускаем и получаем разные иконки для каждого окружения.
Лучшие практики:
Flavors - это не про «сделать красиво», а про контроль и безопасность. Правильная настройка окружений убережет от случайных деплоев с тестовыми данными и позволит команде спокойно работать, не боясь что-то сломать в бою. Один раз настроив, вы сэкономите часы нервотрепки и багов на пустом месте.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Пользователи редко пишут в поддержку с благодарностью о том, что приложение хорошо работает, а вот жалобы на перегрев и разряд батареи прилетают регулярно. И если телефон пользователя начинает нагреваться через пять минут после запуска - это не особенность платформы, это проблемы в коде. Разбираемся, что именно заставляет устройство работать на пределе и как это починить без полного переписывания.
Слишком частые перестройки виджетов:
Flutter перерисовывает UI каждый раз, когда меняется состояние. Это нормально. Проблема начинается там, где перерисовывается все, хотя изменилась мелочь. Один лишний setState на родительском виджете и вся иерархия перестраивается заново. Сотни таких перестроек в секунду и процессор работает на износ.
Что делать: дробить UI на мелкие виджеты, использовать const где возможно, подключать умное управление состоянием (Riverpod, Bloc), чтобы обновлялись только те части экрана, которым это действительно нужно.
Анимации, которые не знают отдыха:
Красивая бесконечная анимация - гордость разработчика, но кошмар для батареи. Особенно если таких анимаций несколько и они продолжают работать даже тогда, когда пользователь ушёл на другой экран или свернул приложение. GPU не отдыхает, телефон греется.
Решение: всегда останавливать анимации в dispose, при возможности приостанавливать их, когда виджет не в фокусе, и не злоупотреблять тяжелыми Lottie-файлами там, где можно обойтись простыми переходами.
Сетевые запросы, которые грузят сервер без продыху:
Каждый запрос к сети - это пробуждение радио-модуля, парсинг JSON, обновление UI. Если приложение опрашивает сервер каждые пару секунд, телефон будет греться даже в фоне. Особенно больно, когда запросы делаются прямо в build или без кэширования.
Выход: выносить сеть из build, использовать кэширование, реже опрашивать сервер, а для real-time фич переходить на WebSockets, которые работают эффективнее частых REST-запросов.
Тяжелые изображения и видео:
Загрузить картинку в полном разрешении и отобразить ее как есть - легко. Но GPU придется каждый раз масштабировать этот гигантский файл, тратя на это ресурсы. Если таких картинок в списке много - телефон начнет нагреваться очень быстро.
Исправление: изменять размер изображений на лету (cacheWidth, cacheHeight), сжимать, использовать отложенную загрузку и не запускать видео автоматически в каждом элементе списка.
Перегрев телефона - это не приговор и не баг платформы. Это следствие того, как написан код. Чаще всего проблемы решаются точечными правками: убрать лишние перестройки, остановить анимации, оптимизировать сеть и изображения. Один раз разобравшись с этими паттернами, вы не только спасете батарею пользователей, но и сделаете приложение быстрее и приятнее. А пользователи будут благодарны не только в отзывах, но и своим теплым, но не горячим телефоном.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2❤1🔥1
Вышла новая версия плагина для VS Code, и в ней снова доработали то, что бесит больше всего - скорость, тесты и повседневные мелочи. Никаких революций, но десяток мелких улучшений, которые в сумме делают работу заметно комфортнее.
Тесты теперь работают адекватно:
В этом обновлении тестам уделили особое внимание. Исправили несколько раздражающих багов: тесты больше не выдают ошибку Cannot read properties of null в консоли, не пропадают из панели результатов и не помечаются ошибочно как пропущенные.
Главное - тесты стали обнаруживаться значительно быстрее в больших проектах. Особенно заметно, если на диске работает антивирус, который раньше мог тормозить процесс. Теперь это должно уйти.
Для тех, кто использует test_reflective_loader, тесты теперь группируются по классам - навигация по результатам становится чище.
Параллельные действия:
Команда Get Packages for All Projects теперь умеет запускать несколько процессов одновременно. Раньше пакеты подтягивались последовательно для каждого проекта, что могло затягиваться. Теперь все летает параллельно, используя до половины ядер процессора.
Редактор и навигация:
Несколько мелочей, которые важны в ежедневной работе:
Работа с эмуляторами:
Убрали лишние запросы к эмуляторам до того, как управление устройствами реально включено. Это должно уменьшить количество таймаутов, когда система только стартует.
Совместимость и старые версии:
Поддержка SDK ниже Dart 3.2 / Flutter 3.16 окончательно прекращена. Если вы все еще сидите на древних версиях, придется либо обновляться, либо откатывать плагин до старой версии - на сайте есть таблица совместимости.
Что будет в будущих SDK:
Некоторые фичи уже есть в бета-версиях, но в стабильных появятся позже:
Очередное обновление, которое не кричит о себе, но делает работу с Flutter в VS Code чуть более предсказуемой и быстрой. Особенно радуют правки тестов и параллельные операции. Если вы активно используете VS Code для разработки - обновляйтесь, мелочи действительно имеют значение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1
Google анонсировала Genkit Dart - open-source фреймворк для создания полноценных ИИ-приложений на Dart и Flutter. Это не просто очередная обертка над API, а инструмент, который позволяет строить сложные ИИ-сценарии с типизацией, тестированием и удобным UI для отладки. Пока в предварительной версии, но уже выглядит многообещающе.
Что такое Genkit Dart и зачем он нужен:
Сейчас ИИ-функции проникают повсюду: кто-то строит вокруг них новые продукты, кто-то добавляет умные фичи в существующие. Genkit Dart закрывает сразу несколько потребностей:
Как это работает:
Фреймворк предлагает несколько сценариев использования, в зависимости от того, где должна выполняться ИИ-логика и как вы хотите управлять ключами.
Все внутри Flutter (для прототипов):
Самый простой способ - писать всю логику прямо в приложении. Подходит для прототипов или случаев, когда пользователь сам вводит свой API-ключ. Но здесь есть важное предупреждение: публиковать в сторе приложение с зашитым ключом - плохая идея, его легко вытащат.
Бэкенд + Flutter с общей типизацией:
Когда логика сложная или ключи нужно прятать, весь ИИ-код уезжает на сервер. Flutter-приложение вызывает его как удаленный метод. Благодаря тому, что и фронт, и бэк на Dart, можно переиспользовать общие схемы данных и сохранить строгую типизацию от конца до конца.
Прокси-сервер для моделей:
Компромиссный вариант: на сервере поднимается тонкая прослойка, которая проксирует запросы к ИИ-моделям, добавляя авторизацию и валидацию. Ключи API хранятся на сервере, а Flutter-приложение общается с ним как с обычным Genkit-клиентом.
Genkit Dart - это попытка внести порядок в хаос ИИ-разработки. Вместо того чтобы каждый раз городить свои обертки над моделями, можно взять готовый фреймворк с типизацией, тестируемостью и удобным UI. Пока это превью, но направление выглядит правильным. Если вы работаете с Dart/Flutter и думаете, как добавить в проект ИИ-фичи - присмотритесь.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1
This media is not supported in your browser
VIEW IN TELEGRAM
С выходом iOS 26 компания Apple представила дизайн Liquid Glass - ту самую жидкую стеклянную эстетику, которая делает интерфейсы объемными и тактильно приятными. Сообщество Flutter все это время искало способ повторить это на своей платформе. Попытки были, но с ограничениями: кто-то завязывался на Impeller и терял поддержку Windows и Web, кто-то просто делал обычное размытие, выдавая его за жидкое стекло. Теперь появилось работающее кроссплатформенное решение.
Что раньше:
Краткий обзор того, что предлагалось раньше:
Все они либо не были кроссплатформенными, либо не давали нужного эффекта.
Что появилось сейчас:
Пакет liquid_glass_easy делает именно то, что заявлено: настоящие интерактивные линзы из жидкого стекла с физикой преломления, искажения и реакции на касания. Работает на Android, iOS, Web, macOS и Windows. В основе - GPU-шейдеры, так что производительность остается высокой даже при нескольких активных линзах.
Как это устроено:
Все строится вокруг двух виджетов:
Линзу можно сделать перетаскиваемой, анимировать через контроллер, накладывать поверх любого контента. Все настраивается до мелочей.
Жидкое стекло во Flutter наконец-то перестало быть чем-то, что можно только представить в воображении. liquid_glass_easy дает рабочий инструмент, который не требует жертвовать кроссплатформенностью и производительностью. Да, это не та фича, ради которой пользователь побежит скачивать приложение, но когда хочется добавить интерфейсу глубины и тактильности, теперь есть куда смотреть. Для дизайнерских экспериментов и вау-эффекта - вполне.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤1👍1
Один из самых частых источников багов во Flutter - потеря состояния при перестройке списков или перестановке элементов. Кажется, все работает, но при добавлении новой карточки счетчик перескакивает на другую. Или при изменении порядка чекбоксы остаются отмеченными не там. Чаще всего проблема решается при помощи Keys. Но использовать их бездумно - тоже плохая идея.
Для чего используются Keys:
Flutter при обновлении экрана сравнивает старый и новый список виджетов и пытается понять, что изменилось. По умолчанию он ориентируется на тип виджета и его позицию в дереве. Это быстро, но приводит к ошибкам, когда элементы одного типа меняются местами или добавляются новые.
Keys дают Flutter дополнительную информацию: вместо «третий элемент в списке» он ищет «элемент с таким-то идентификатором». Благодаря этому состояние прикрепляется к конкретному объекту, а не к индексу.
Типы ключей и когда их выбирать:
Где без ключей не обойтись:
Где ключи не нужны:
Чего делать не стоит:
Не надо оборачивать каждый виджет в Key просто потому, что так можно. Лишние ключи усложняют алгоритмы сравнения и могут замедлить рендеринг. Особенно это касается GlobalKey - его наличие в каждом втором виджете быстро приведет к утечкам и падению производительности.
Keys - это инструмент для точечного решения проблем с идентификацией виджетов. Если при перестройке интерфейса состояние прыгает или теряется - скорее всего, нужен ValueKey. Если нужно сбросить внутреннее состояние - поможет UniqueKey. А если без доступа к виджету из другого места не обойтись - придется использовать GlobalKey. Во всех остальных случаях лучше обойтись без них.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
Flutter хорош тем, что один код работает на двух платформах. Но рано или поздно наступает момент, когда нужно сделать что-то нативное: получить модель устройства, подключиться к Bluetooth, считать данные с датчиков. Здесь на помощь приходят платформенные каналы - механизм, который позволяет Dart и нативному коду обмениваться сообщениями.
Как устроен этот мост:
Все взаимодействие строится вокруг каналов. Это не магия, а просто способ передавать сообщения туда и обратно. Dart-код отправляет запрос, нативная сторона его обрабатывает и возвращает ответ. Все данные при этом сериализуются (превращаются в понятный для обеих сторон формат) и десериализуются обратно.
Самый частый сценарий - метод-канал (MethodChannel). Это как вызов функции, но на удаленной стороне. Вызываете метод с именем, передаете параметры, ждете ответа. Все асинхронно, то есть приложение не зависает, пока нативная часть думает.
Когда нужен MethodChannel:
Если нужно разово что-то запросить у системы - модель телефона, версию ОС, разрешение - это к MethodChannel. Работает просто: на стороне Dart создается канал с уникальным именем (обычно используют обратную доменную нотацию, чтобы не пересекаться с другими плагинами). Потом вызывается метод, и в ответ приходит результат или ошибка.
В нативной части (Android на Kotlin, iOS на Swift) этот же канал регистрируется, и для каждого вызова прописывается обработчик. Если метод известен - возвращается результат, если нет - вызывается notImplemented.
Когда нужен EventChannel:
Бывают ситуации, когда данные приходят не по запросу, а сами. Например, акселерометр или датчик движения - они отправляют показатели постоянно, пока подписка активна. Здесь пригождается EventChannel.
Flutter подписывается на поток, нативная сторона начинает слать события через специальный объект (eventSink). Как только подписка отменяется, поток закрывается. Это идеально для датчиков, геолокации, состояния батареи - всего, что меняется во времени.
Платформенные каналы - это не страшно. MethodChannel закрывает задачи «спросили - получили», EventChannel - «подписались - получаем поток». Главное - помнить про асинхронность, типы данных и не перегружать главный поток. Если нужна сложная логика, лучше вынести ее в нативную часть, а в Dart только вызывать и получать результат. А еще - всегда оборачивать вызовы в try-catch, потому что нативная сторона может вернуть ошибку.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2❤1
С августа 2026 года установка APK-файлов от неизвестных разработчиков на Android станет сложнее. Google вводит продвинутый процесс, который должен защитить пользователей от мошенников, но заодно превращает установку любого приложения не из Google Play в квест.
Это касается не только нативных разработчиков, но и разработчиков на Flutter, которые собирают приложения под Android и которые распространяют свои приложения в обход Google Play (например через сайты, соц. сети или телеграм). Это означает, что привычный способ «включил неизвестные источники -> установил» больше не сработает. Вместо этого - сутки ожидания, биометрия и подтверждение, что вас никто не принуждает.
Что изменится:
Раньше достаточно было включить разрешение на установку из неизвестных источников и можно было ставить любой APK. Теперь нужно будет пройти целую процедуру:
Только после этого можно будет устанавливать приложения от неизвестных разработчиков. И то - каждые семь дней процедуру, возможно, придется повторять.
Почему ввели данный процесс:
Google объясняет это борьбой с мошенниками. По статистике Global Anti-Scam Alliance, 57% взрослых сталкивались с мошенничеством за последний год, а ущерб составил 442 миллиарда долларов. Мошенники часто давят на жертв по телефону, заставляя прямо сейчас отключить защиту и установить вредоносное приложение. Принудительная пауза в сутки должна сломать эту схему.
Для тех, кто просто хочет установить приложение от независимого разработчика, это кажется излишним и выглядит как наказание.
Android теряет одну из главных своих особенностей - свободу установки любого приложения без ограничений. Теперь это будет возможно только после процедуры с суточным ожиданием. Google говорит о безопасности и это действительно важная тема. Для нативных разработчиков и Flutter-разработчиков, которые тестируют сборки на реальных устройствах, раздают бета-версии клиентам через телеграм или просто устанавливают собственные APK в процессе разработки, это ощущается как шаг назад. В погоне за защитой от мошенников страдают в том числе разработчики, которым нужна возможность быстро ставить приложения не из магазина.
Please open Telegram to view this post
VIEW IN TELEGRAM
👀4🙏2👍1🗿1
В Dart есть ключевое слово covariant, о котором многие слышали, но используют редко. А зря, оно решает конкретную проблему с переопределением методов в наследниках, когда нужно уточнить тип параметра. Разбираемся, как это работает и в каких случаях пригождается.
В чем суть проблемы:
Представьте, что у вас есть базовый класс Employee с методом process, который принимает любой тип документа (Document). Вы создаете наследника Manager, который по логике должен работать только с отчетами (Report), а не с любыми документами.
По умолчанию Dart этого не позволит. Метод в наследнике должен принимать тот же тип, что и в родителе - Document. Если вы попытаетесь сузить тип до Report, компилятор выдаст ошибку.
class Employee {
void process(Document doc) {}
}
class Manager extends Employee {
@override
void process(Report doc) {} // ошибка переопределения
}
Что делает covariant:
Ключевое слово covariant говорит компилятору: «Этот параметр может быть сужен в наследниках». Добавляем его в базовый класс и все работает:
class Employee {
void process(covariant Document doc) {}
}
class Manager extends Employee {
@override
void process(Report doc) {} // теперь можно
}
Теперь метод process у Manager принимает только Report. Попытка передать Invoice вызовет ошибку типов.
Когда это полезно:
Ситуации, когда нужно уточнить тип параметра в наследнике, возникают не так часто, но бывают. Например:
Без covariant пришлось бы делать приведение типов внутри метода или проверять тип вручную. С ним код становится чище и типобезопаснее.
covariant - инструмент на случай, когда нужно уточнить тип параметра в наследнике, не ломая контракт базового класса. В повседневной разработке он нужен нечасто, но знание о нем помогает писать более точный и типобезопасный код. Если вы когда-нибудь ловили себя на мысли «хотелось бы указать в наследнике более конкретный тип», то covariant - это именно то, что нужно.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2❤1
Для многих начинающих разработчиков BuildContext остается чем-то вроде магической переменной - появляется из ниоткуда, что-то делает, но как именно непонятно. На самом деле это интерфейс к элементу в дереве виджетов. Когда вы пишете виджет, вы описываете конфигурацию. А context - это ваш пропуск к тому, что реально существует в памяти.
Как на самом деле работает поиск:
Когда вы вызываете Theme.of(context), Flutter начинает подниматься вверх по дереву от текущего контекста, пока не найдет ближайшего предка нужного типа. Если у вас вложенные темы, context определяет, какую из них вы получите.
Отсюда и берутся проблемы: Navigator.of(context) иногда не работает, потому что контекст находится выше того навигатора, который вы пытаетесь использовать. Или Scaffold.of(context) не видит Scaffold, потому что context создан раньше.
Где чаще всего спотыкаются:
BuildContext - это не магия, а просто доступ к элементу в дереве. Понимание того, как Flutter ищет предков, как работает mounted и когда контекст можно использовать - это база, без которой в больших проектах не обойтись. Ошибки с контекстом - одни из самых частых у новичков. И они решаются не гаданием, а пониманием того, что на самом деле происходит под капотом.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2🔥1
В повседневной работе мы привыкли к Column, Row, ListView. Они закрывают большинство задач по построению интерфейсов. Но иногда требуется настоящая таблица: строки, столбцы, сортировка, постраничная навигация. И здесь у Flutter есть несколько специализированных инструментов, о которых многие забывают.
DataTable - для небольших объемов:
Если у вас предсказуемый, небольшой набор данных - идеальный вариант. DataTable строится на основе DataRow и DataCell, все объявляется декларативно. Подходит для экранов настроек, административных панелей, любых мест, где таблица не превышает десятка строк. Сортировка подключается через onSort, постраничное отображение контента - через PaginatedDataTable, которая оборачивает обычную DataTable и добавляет навигацию.
Table - полный контроль:
Если нужно управлять каждой ячейкой, задавать разную ширину колонок, рисовать границы, вставлять сложные виджеты - используйте Table. Здесь вы сами определяете каждую строку как TableRow, а внутри - список ячеек с любыми виджетами. Можно задавать ширину колонок: фиксированную (FixedColumnWidth), пропорциональную (FlexColumnWidth) или по содержимому (IntrinsicColumnWidth).
Что важно знать:
DataTable и Table - не самые популярные виджеты во Flutter, но в своих нишах они незаменимы. DataTable удобен для небольших, четко структурированных данных с сортировкой и пагинацией. Table - для кастомных макетов, где нужно полное управление шириной и содержимым ячеек. Если объемы большие или содержимое часто меняется, стоит присмотреться к другим подходам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2🔥1
Команда Flutter опубликовала размышления о том, как искусственный интеллект влияет на развитие экосистемы. Это не дорожная карта, а скорее честный взгляд на текущую ситуацию. Потому что в 2026 году невозможно делать инструменты для разработки, не обращая внимания на ИИ.
Цифры, которые объясняют все:
Согласно опросам, 84% разработчиков в целом используют ИИ-инструменты в своей работе. Среди Flutter-разработчиков этот показатель чуть ниже - 79%, но все равно впечатляет. Однако есть проблема: 46% не доверяют точности ИИ при решении критических задач. Это тратит лишнее время на проверку сгенерированного кода.
Главные принципы:
Команда декларирует несколько ключевых правил, которым следует при развитии ИИ-направления:
Команда Flutter не пытается предсказать будущее ИИ, а экспериментирует на виду, честно говоря о своих намерениях. ИИ не станет обязательной частью экосистемы, но для тех, кто хочет его использовать, инструменты будут. И при этом никто не заставляет отказываться от традиционной разработки - это тоже полностью валидный путь. Главное - чтобы у разработчика был выбор.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🙏1👀1
В каждом проекте рано или поздно появляются серые, поблекшие импорты. Они висят, ни на что не влияют, но глаза мозолят. Ревьюеры тратят время на проверку, нужны ли они вообще. А кодовая база обрастает балластом, который никто не замечает, но всем мешает.
Одна команда, которая все решает:
В корне проекта достаточно выполнить:
dart pub get && dart fix --apply
Анализатор Dart пробежится по всем файлам, найдет неиспользуемые импорты и удалит их. Без лишних вопросов, без ручного перебора каждого файла.
Если хочется сначала посмотреть, что именно будет удалено, можно выполнить dart fix --dry-run. Покажет список изменений, но ничего не тронет.
Почему об этом вообще стоит думать:
Неиспользуемые импорты не ломают код, но они делают его грязным. Ревьюеры тратят время на проверку того, что на самом деле не используется. Линтеры и форматтеры работают хуже, когда списки импортов захламлены. А сам проект со временем становится тяжелее и менее понятным.
dart fix решает эту проблему мгновенно. Инструмент официальный, встроенный в экосистему Dart, так что никаких сторонних зависимостей тащить не нужно.
Что важно помнить:
Перед массовой чисткой лучше сделать коммит - мало ли что. Сгенерированные файлы (.g.dart) dart fix трогать не должен, они все равно перезапишутся при следующей сборке. И всегда после чистки стоит прогнать dart analyze && flutter test, чтобы убедиться, что ничего не сломалось.
dart fix --apply - это не магия, а просто правильный инструмент. Он не делает код быстрее и не добавляет новых фич. Зато он убирает мусор, который отвлекает, запутывает и создает иллюзию сложности. Если в вашем проекте есть неиспользуемые импорты - команда решит проблему за секунду. Если их нет - вы либо уже все почистили, либо просто не замечаете.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
Команда Flutter объявила о заморозке изменений в библиотеках Material и Cupertino внутри основного SDK. Это первый шаг к самому масштабному архитектурному изменению в истории фреймворка - полному отделению дизайн-систем от ядра. Теперь Material и Cupertino станут обычными пакетами на
pub.dev.Какую проблему решает это изменение:
Сейчас Material и Cupertino жестко привязаны к Flutter и обновляются только с релизами SDK. Это создает несколько проблем:
После разделения библиотеки Material и Cupertino будут обычными пакетами на
pub.dev со своим версионированием и циклом обновлений.Что будет происходить дальше:
С 7 апреля все изменения в Material и Cupertino внутри Flutter заморожены. Дальнейшая разработка продолжится в репозитории flutter/packages, где появятся новые пакеты - material_ui и cupertino_ui. После выхода стабильного релиза Flutter 3.44 новые пакеты станут доступны, и разработчикам нужно будет постепенно переходить на них.
Старые библиотеки Material и Cupertino в SDK будут объявлены устаревшими в следующем релизе после 3.44 и удалены спустя какое-то время.
Flutter перестает быть фреймворком со встроенными Material и Cupertino и становится платформой, где дизайн-системы живут своей жизнью. Это не просто техническое изменение, а смена подхода: ядро SDK становится легче и стабильнее, а дизайн-системы - независимыми, с собственными циклами обновлений. Разработчики получают свободу выбора: можно использовать Material, Cupertino или свою собственную дизайн-систему. Баги теперь будут фикситься быстрее - не нужно ждать квартального релиза Flutter.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2👀1
Загружая новую сборку iOS-приложения, всегда приходится заходить в App Store Connect для нажатия на «Нет» в окне «Информация о соответствии экспортным требованиям».
Если ваше приложение не использует шифрование, то можно очень просто избавиться от ручного подтверждения при каждой загрузке сборки в TestFlight.
Для этого необходимо открыть файл Info.plist в папке /ios/Runner и добавить следующие строки:
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
Что это дает:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3🔥2
Производительность Flutter-приложения напрямую зависит от того, как написан код. Лишние перестройки UI, тяжелые операции в основном потоке, неправильная работа со списками и изображениями - все это ведет к фризам, падению FPS и раздраженным пользователям. В этом посте обсудим наиболее распространенные ошибки, которые превращают быстрый фреймворк в тормознутое приложение.
Лишние перестройки UI:
Самая частая проблема - setState, который пересобирает все дерево виджетов целиком. Даже если изменился один текст, Flutter заново вызывает build() для всех дочерних элементов. В маленьком проекте это незаметно. Когда же внутри есть списки, картинки и сложные layout'ы, каждое нажатие кнопки начинает тормозить интерфейс. Решение - использовать ValueListenableBuilder, StreamBuilder или аналоги, которые обновляют только нужную часть.
Отсутствие const:
Многие забывают про const. Без него каждый rebuild создает новые объекты виджетов, даже если они идентичны предыдущим. Это увеличивает нагрузку на сборщик мусора и процессор. В больших списках или сложных UI это дает заметный прирост производительности - достаточно просто добавить const там, где это возможно.
Логика внутри build():
build() может вызываться десятки раз в секунду - при анимациях, скролле, обновлениях. Если внутри выполнять сортировку, фильтрацию или парсинг, это напрямую убивает производительность. Даже простая операция sort() на среднем списке может занимать миллисекунды, а для 60 FPS на каждый кадр есть всего 16 мс. Вся логика должна быть вынесена в initState или бизнес-слой.
ListView без builder:
Когда вы используете ListView(children: [...]), Flutter создает все элементы списка сразу, даже если пользователь видит только первые 5–10. При 100+ элементах это приводит к лишним аллокациям, перегрузке памяти и долгому первому рендеру. ListView.builder создает элементы лениво - только те, что видны на экране. Это значительно снижает нагрузку.
Отсутствие ключей:
Без key Flutter не может корректно сопоставить старые и новые элементы при обновлении списка. В результате он пересоздает виджеты вместо их обновления, что приводит к лишним rebuildам и визуальным багам - например, прыгающим элементам. ValueKey или ObjectKey решают эту проблему.
Большинство проблем с производительностью возникают не из-за сложности задачи, а из-за мелких решений, которые легко упустить в процессе разработки. Лишний rebuild, тяжелая операция в основном потоке, список без builder - каждое из этих решений кажется безобидным, пока приложение не начинает тормозить. Хорошая новость в том, что большинство описанных проблем решаются относительно просто. Главное - не откладывать это на потом.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2❤1🙏1
В повседневной разработке часто встречаются задачи, которые можно решить красиво и без лишнего кода. Вместо того чтобы городить велосипеды, достаточно знать несколько встроенных инструментов Flutter.
LayoutBuilder - адаптивный интерфейс без хардкода:
Проблема: нужно показывать разную верстку в зависимости от ширины экрана. Многие начинают писать проверки через MediaQuery или пытаются угадать размеры устройства. Но это неправильно - важно не само устройство, а реальное место, которое виджет занимает на экране.
LayoutBuilder дает доступ к ограничениям родителя прямо во время построения. Вы можете посмотреть максимальную ширину и решить, показывать горизонтальное меню или вертикальное, две колонки или одну. Все адаптируется под текущий контейнер, а не под экран в целом.
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(children: [sidebar, content]);
}
return Column(children: [sidebar, content]);
},
)
AnimatedSwitcher - плавные переходы между виджетами:
Смена одного виджета на другой обычно выглядит резко. Текст изменился - моргнул, иконка сменилась - тоже моргнула. AnimatedSwitcher добавляет анимацию при замене дочернего элемента. Старый виджет плавно исчезает, новый - появляется. Вы можете настроить тип перехода: затухание, сдвиг, масштаб.
Важный момент: анимация сработает только если у виджетов разные key. Иначе AnimatedSwitcher решит, что ничего не изменилось.
AnimatedSwitcher(
duration: Duration(milliseconds: 300),
child: Text(counter.toString(), key: ValueKey(counter)),
)
Все эти виджеты решают повседневные задачи: адаптивную верстку, плавную смену контента, простые анимации и оптимизацию перерисовок. Они есть в стандартной библиотеке, не требуют подключения сторонних пакетов и при этом заметно упрощают код. Если вы до сих пор писали свои велосипеды для таких случаев - попробуйте заменить их на встроенные решения.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2🙏1
При разработке Flutter-приложений паттерн BLoC часто становится всемогущим объектом, впитывающим всю бизнес-логику. Внутри хендлеров оказываются и запросы к сервисам, и валидация и эмиттеры состояния. Проект разрастается, файлы раздуваются, тестирование становится невозможным. Сегодня обсудим как можно вынести бизнес-логику в отдельные классы - use-cases.
Как это работает:
Вместо того чтобы вызывать сервисы прямо внутри хендлеров BLoC, вся логика конкретного сценария (например загрузки товаров) выносится в отдельный класс. Use-case зависит от абстракций репозиториев и сервисов, но ничего не знает про UI. Он вызывает нужные зависимости, обрабатывает ошибки, выполняет side-эффекты и только после этого отправляет событие в BLoC. Сам BLoC превращается в тонкую прослойку: принимает события, обновляет состояние и больше ничего не делает.
Как это работает на практике:
Огромный BLoC-файл, отвечающий за получение данных, кэширование, фильтрацию и обновление UI, превращается в узкое место проекта. Конструктор забит зависимостями, тестирование почти невозможно. После рефакторинга BLoC сокращается до 20-30 строк, не зависит от сервисов и становится просто набором функций для обновления состояния. Все пользовательские сценарии выносятся в отдельные use-cases.
В результате время разработки нового функционала сокращается, количество багов снижается, тесты становятся надежнее.
Почему это работает:
Use-case оркестрирует несколько сервисов и репозиториев, объединяет данные, обрабатывает ошибки, логирует и только после этого отправляет событие в BLoC. BLoC остается только стейт-менеджером и не выполняет ничего, кроме преобразования событий в состояние. Такой подход соответствует принципам чистой архитектуры: доменный слой не зависит от реализации, что повышает гибкость и тестируемость.
Разделение бизнес-логики и UI - необходимость для масштабируемых приложений. Use-cases помогают структурировать код, упрощают тестирование и делают BLoC максимально простым. Этот подход не привязан к BLoC и может использоваться с любым другим стейт-менеджером.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤1👍1
Команда Flutter объявила о миграции трех основных своих сайтов (dart.dev, flutter.dev и docs.flutter.dev) на Jaspr - open-source фреймворк для создания веб-сайтов на Dart. Раньше сайты были собраны из разных технологий: документация работала на Eleventy (Node.js), а основной сайт - на Wagtail (Python + Django). Теперь все на Dart.
Почему они решили это сделать:
Старая архитектура была фрагментированной. Чтобы вносить правки или поддерживать сайты, нужно было знать
Node.js, Python и Dart одновременно. Это создавало барьер для контрибьюторов и усложняло поддержку. Кроме того, добавление интерактивных элементов (например, викторин в туториалах) требовало сложных, разовых решений.Что изменилось:
Теперь все три сайта используют единый стек на Dart. Основные изменения:
Почему так лучше:
Миграция на Jaspr - пример того, как сообщество и официальная команда совместно улучшают экосистему. Единый стек на Dart упрощает поддержку, снижает порог входа для контрибьюторов и открывает возможности для более интерактивной документации. Если вы когда-нибудь хотели попробовать веб-разработку на Dart - теперь есть отличный повод.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2