Flutter & Dart | Мобильный трудоголик
404 subscribers
29 photos
1 video
82 links
Пишу простым языком про разработку на Flutter & Dart (iOS, Android, macOS, Windows) и мобильную разработку в целом.
Обо мне: https://t.me/hardworkerFlutter/2
Чат: @flutterDevChat
Другие мои каналы: @hardworkerIT и @itDenisov
Download Telegram
👣 Keys во Flutter: как не потерять состояние при перестройке списков

Один из самых частых источников багов во Flutter - потеря состояния при перестройке списков или перестановке элементов. Кажется, все работает, но при добавлении новой карточки счетчик перескакивает на другую. Или при изменении порядка чекбоксы остаются отмеченными не там. Чаще всего проблема решается при помощи Keys. Но использовать их бездумно - тоже плохая идея.


Для чего используются Keys:

Flutter при обновлении экрана сравнивает старый и новый список виджетов и пытается понять, что изменилось. По умолчанию он ориентируется на тип виджета и его позицию в дереве. Это быстро, но приводит к ошибкам, когда элементы одного типа меняются местами или добавляются новые.

Keys дают Flutter дополнительную информацию: вместо «третий элемент в списке» он ищет «элемент с таким-то идентификатором». Благодаря этому состояние прикрепляется к конкретному объекту, а не к индексу.


Типы ключей и когда их выбирать:

🔵ValueKey - самый частый выбор. Берет какое-то стабильное значение (id, уникальный заголовок) и использует его как идентификатор. Идеально для списков, где у каждого элемента есть уникальный ключ из данных.

🔵ObjectKey - использует сам объект в качестве идентификатора, сравнивая его через стандартный оператор ==. Пригождается, когда у элемента нет уникального поля (например id), но сам объект достаточно стабилен и не меняется в процессе работы.

🔵UniqueKey - каждый раз создает новый идентификатор. Это гарантирует, что Flutter не будет пытаться сопоставить виджет с предыдущим, а создаст новый элемент с нуля. Удобно, когда нужно принудительно сбросить состояние (например пересоздать анимацию), но использовать на каждый чих не стоит - производительность пострадает.

🔵GlobalKey - тяжелая артиллерия. Позволяет получить доступ к состоянию виджета из любой точки приложения. Нужен для сложных сценариев: работа с формами, программная навигация, тестирование. Но каждый такой ключ хранится глобально и не очищается автоматически, поэтому их количество должно быть минимальным.


Где без ключей не обойтись:

🔵Списки, где элементы можно переставлять, добавлять или удалять.

🔵Виджеты, которые меняют порядок в зависимости от условий.

🔵Любые места, где важно сохранить состояние за конкретным экземпляром данных.


Где ключи не нужны:

🔵Статичные списки, которые не меняются.

🔵Виджеты без внутреннего состояния (статусные иконки, просто текст).

🔵Случаи, где состояние вообще не важно.


Чего делать не стоит:

Не надо оборачивать каждый виджет в Key просто потому, что так можно. Лишние ключи усложняют алгоритмы сравнения и могут замедлить рендеринг. Особенно это касается GlobalKey - его наличие в каждом втором виджете быстро приведет к утечкам и падению производительности.


💡 Вывод:

Keys - это инструмент для точечного решения проблем с идентификацией виджетов. Если при перестройке интерфейса состояние прыгает или теряется - скорее всего, нужен ValueKey. Если нужно сбросить внутреннее состояние - поможет UniqueKey. А если без доступа к виджету из другого места не обойтись - придется использовать GlobalKey. Во всех остальных случаях лучше обойтись без них.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤1
👣 Flutter и нативный код: как работают MethodChannel и EventChannel

Flutter хорош тем, что один код работает на двух платформах. Но рано или поздно наступает момент, когда нужно сделать что-то нативное: получить модель устройства, подключиться к Bluetooth, считать данные с датчиков. Здесь на помощь приходят платформенные каналы - механизм, который позволяет Dart и нативному коду обмениваться сообщениями.


Как устроен этот мост:

Все взаимодействие строится вокруг каналов. Это не магия, а просто способ передавать сообщения туда и обратно. Dart-код отправляет запрос, нативная сторона его обрабатывает и возвращает ответ. Все данные при этом сериализуются (превращаются в понятный для обеих сторон формат) и десериализуются обратно.

Самый частый сценарий - метод-канал (MethodChannel). Это как вызов функции, но на удаленной стороне. Вызываете метод с именем, передаете параметры, ждете ответа. Все асинхронно, то есть приложение не зависает, пока нативная часть думает.


Когда нужен MethodChannel:

Если нужно разово что-то запросить у системы - модель телефона, версию ОС, разрешение - это к MethodChannel. Работает просто: на стороне Dart создается канал с уникальным именем (обычно используют обратную доменную нотацию, чтобы не пересекаться с другими плагинами). Потом вызывается метод, и в ответ приходит результат или ошибка.

В нативной части (Android на Kotlin, iOS на Swift) этот же канал регистрируется, и для каждого вызова прописывается обработчик. Если метод известен - возвращается результат, если нет - вызывается notImplemented.


Когда нужен EventChannel:

Бывают ситуации, когда данные приходят не по запросу, а сами. Например, акселерометр или датчик движения - они отправляют показатели постоянно, пока подписка активна. Здесь пригождается EventChannel.

Flutter подписывается на поток, нативная сторона начинает слать события через специальный объект (eventSink). Как только подписка отменяется, поток закрывается. Это идеально для датчиков, геолокации, состояния батареи - всего, что меняется во времени.


🔗 Читать подробнее


💡 Вывод:

Платформенные каналы - это не страшно. MethodChannel закрывает задачи «спросили - получили», EventChannel - «подписались - получаем поток». Главное - помнить про асинхронность, типы данных и не перегружать главный поток. Если нужна сложная логика, лучше вынести ее в нативную часть, а в Dart только вызывать и получать результат. А еще - всегда оборачивать вызовы в try-catch, потому что нативная сторона может вернуть ошибку.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2❤1
🏋️ Установка APK на Android усложняется: придется ждать сутки

С августа 2026 года установка APK-файлов от неизвестных разработчиков на Android станет сложнее. Google вводит продвинутый процесс, который должен защитить пользователей от мошенников, но заодно превращает установку любого приложения не из Google Play в квест.

Это касается не только нативных разработчиков, но и разработчиков на Flutter, которые собирают приложения под Android и которые распространяют свои приложения в обход Google Play (например через сайты, соц. сети или телеграм). Это означает, что привычный способ «включил неизвестные источники -> установил» больше не сработает. Вместо этого - сутки ожидания, биометрия и подтверждение, что вас никто не принуждает.


Что изменится:

Раньше достаточно было включить разрешение на установку из неизвестных источников и можно было ставить любой APK. Теперь нужно будет пройти целую процедуру:

🔵Включить режим разработчика.

🔵Подтвердить, что вас никто не принуждает.

🔵Перезагрузить телефон.

🔵Подождать сутки.

🔵Пройти биометрическую проверку.

Только после этого можно будет устанавливать приложения от неизвестных разработчиков. И то - каждые семь дней процедуру, возможно, придется повторять.


Почему ввели данный процесс:

Google объясняет это борьбой с мошенниками. По статистике Global Anti-Scam Alliance, 57% взрослых сталкивались с мошенничеством за последний год, а ущерб составил 442 миллиарда долларов. Мошенники часто давят на жертв по телефону, заставляя прямо сейчас отключить защиту и установить вредоносное приложение. Принудительная пауза в сутки должна сломать эту схему.

Для тех, кто просто хочет установить приложение от независимого разработчика, это кажется излишним и выглядит как наказание.


🔗 Читать подробнее


💡 Вывод:

Android теряет одну из главных своих особенностей - свободу установки любого приложения без ограничений. Теперь это будет возможно только после процедуры с суточным ожиданием. Google говорит о безопасности и это действительно важная тема. Для нативных разработчиков и Flutter-разработчиков, которые тестируют сборки на реальных устройствах, раздают бета-версии клиентам через телеграм или просто устанавливают собственные APK в процессе разработки, это ощущается как шаг назад. В погоне за защитой от мошенников страдают в том числе разработчики, которым нужна возможность быстро ставить приложения не из магазина.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👀4🙏2👍1🗿1
👣 Когда в Dart нужен covariant и как он работает

В 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 - это именно то, что нужно.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2❤1
👣 Что важно знать о BuildContext в Flutter

Для многих начинающих разработчиков BuildContext остается чем-то вроде магической переменной - появляется из ниоткуда, что-то делает, но как именно непонятно. На самом деле это интерфейс к элементу в дереве виджетов. Когда вы пишете виджет, вы описываете конфигурацию. А context - это ваш пропуск к тому, что реально существует в памяти.


Как на самом деле работает поиск:

Когда вы вызываете Theme.of(context), Flutter начинает подниматься вверх по дереву от текущего контекста, пока не найдет ближайшего предка нужного типа. Если у вас вложенные темы, context определяет, какую из них вы получите.

Отсюда и берутся проблемы: Navigator.of(context) иногда не работает, потому что контекст находится выше того навигатора, который вы пытаетесь использовать. Или Scaffold.of(context) не видит Scaffold, потому что context создан раньше.


Где чаще всего спотыкаются:

🔵initState - запретная зона. Нельзя использовать context напрямую в initState. Если нужно что-то показать при открытии экрана, приходится использовать addPostFrameCallback. Иначе приложение упадет.

🔵Асинхронные операции - ловушка. Вы сделали запрос, ждали ответа, а пользователь уже закрыл экран. Если попробовать использовать старый context будет краш. Поэтому после каждого await нужно проверять if (!context.mounted) return;

🔵Диалоги - отдельная история. Чтобы закрыть диалог изнутри, нужно использовать контекст, который приходит в builder, а не тот, что был снаружи. Иначе навигатор не поймет, что именно закрывать.


🔗 Читать подробнее


💡 Вывод:

BuildContext - это не магия, а просто доступ к элементу в дереве. Понимание того, как Flutter ищет предков, как работает mounted и когда контекст можно использовать - это база, без которой в больших проектах не обойтись. Ошибки с контекстом - одни из самых частых у новичков. И они решаются не гаданием, а пониманием того, что на самом деле происходит под капотом.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2🔥1
👣 DataTable и Table: работа с таблицами во Flutter

В повседневной работе мы привыкли к Column, Row, ListView. Они закрывают большинство задач по построению интерфейсов. Но иногда требуется настоящая таблица: строки, столбцы, сортировка, постраничная навигация. И здесь у Flutter есть несколько специализированных инструментов, о которых многие забывают.


DataTable - для небольших объемов:

Если у вас предсказуемый, небольшой набор данных - идеальный вариант. DataTable строится на основе DataRow и DataCell, все объявляется декларативно. Подходит для экранов настроек, административных панелей, любых мест, где таблица не превышает десятка строк. Сортировка подключается через onSort, постраничное отображение контента - через PaginatedDataTable, которая оборачивает обычную DataTable и добавляет навигацию.


Table - полный контроль:

Если нужно управлять каждой ячейкой, задавать разную ширину колонок, рисовать границы, вставлять сложные виджеты - используйте Table. Здесь вы сами определяете каждую строку как TableRow, а внутри - список ячеек с любыми виджетами. Можно задавать ширину колонок: фиксированную (FixedColumnWidth), пропорциональную (FlexColumnWidth) или по содержимому (IntrinsicColumnWidth).


Что важно знать:

🔵IntrinsicColumnWidth - заставляет Flutter делать два прохода: сначала измерить все, потом отрисовать. На сотнях строк это может начать тормозить.

🔵Адаптивность - на узких экранах таблица может стать нечитаемой. Лучше либо предусмотреть горизонтальный скролл, либо на мобильных устройствах заменять таблицу на другой тип компоновки.

🔵Динамическая высота строк - если содержимое ячеек часто меняется, Table может работать неоптимально. Здесь иногда проще собрать свой вариант через ListView + Row.


🔗 Читать подробнее


💡 Вывод:

DataTable и Table - не самые популярные виджеты во Flutter, но в своих нишах они незаменимы. DataTable удобен для небольших, четко структурированных данных с сортировкой и пагинацией. Table - для кастомных макетов, где нужно полное управление шириной и содержимым ячеек. Если объемы большие или содержимое часто меняется, стоит присмотреться к другим подходам.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2🔥1
👣 Как Dart и Flutter смотрят на ИИ в 2026 году

Команда Flutter опубликовала размышления о том, как искусственный интеллект влияет на развитие экосистемы. Это не дорожная карта, а скорее честный взгляд на текущую ситуацию. Потому что в 2026 году невозможно делать инструменты для разработки, не обращая внимания на ИИ.


Цифры, которые объясняют все:

Согласно опросам, 84% разработчиков в целом используют ИИ-инструменты в своей работе. Среди Flutter-разработчиков этот показатель чуть ниже - 79%, но все равно впечатляет. Однако есть проблема: 46% не доверяют точности ИИ при решении критических задач. Это тратит лишнее время на проверку сгенерированного кода.


Главные принципы:

Команда декларирует несколько ключевых правил, которым следует при развитии ИИ-направления:

🔵Человек прежде всего. Dart остается языком, который легко читать и поддерживать человеку, даже если код написан ИИ. Это важно, потому что ИИ-сгенерированный код не должен превращаться в нечитаемую кашу.

🔵Добавлять, а не заменять. ИИ-инструменты должны дополнять опыт разработки, а не вытеснять разработчика. Каждый сам решает, использовать ИИ или нет и в каком объеме. При этом документация и базовые инструменты остаются источником истины.

🔵Открытые стандарты и агентная нейтральность. Flutter должен хорошо работать с любым агентом, не только с Gemini. Для этого используются открытые протоколы вроде MCP. Например, недавно добавили MCP-инструмент для поддержки горячей перезагрузки при разработке с ИИ.

🔵Доверие через качество. Главная проблема ИИ-генерации - затраты времени на проверку. Команда работает над тем, чтобы сгенерированный код был точным, идиоматичным и соответствовал стандартам проекта. Для этого сотрудничают с Google Deepmind и Antigravity по оценке моделей.


🔗 Читать подробнее


💡 Вывод:

Команда Flutter не пытается предсказать будущее ИИ, а экспериментирует на виду, честно говоря о своих намерениях. ИИ не станет обязательной частью экосистемы, но для тех, кто хочет его использовать, инструменты будут. И при этом никто не заставляет отказываться от традиционной разработки - это тоже полностью валидный путь. Главное - чтобы у разработчика был выбор.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1🙏1👀1
👣 Как удалить все неиспользуемые импорты во Flutter-проекте

В каждом проекте рано или поздно появляются серые, поблекшие импорты. Они висят, ни на что не влияют, но глаза мозолят. Ревьюеры тратят время на проверку, нужны ли они вообще. А кодовая база обрастает балластом, который никто не замечает, но всем мешает.


Одна команда, которая все решает:

В корне проекта достаточно выполнить:


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


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1
👣 Material и Cupertino больше не часть SDK Flutter

Команда Flutter объявила о заморозке изменений в библиотеках Material и Cupertino внутри основного SDK. Это первый шаг к самому масштабному архитектурному изменению в истории фреймворка - полному отделению дизайн-систем от ядра. Теперь Material и Cupertino станут обычными пакетами на pub.dev.


Какую проблему решает это изменение:

Сейчас Material и Cupertino жестко привязаны к Flutter и обновляются только с релизами SDK. Это создает несколько проблем:

🔵Зависимость от цикла релизов. Нашли баг в Material? Ждите три месяца, пока выйдет новый релиз Flutter. Нужна свежая версия Material 3? Обновляйте весь SDK, даже если вам это не нужно.

🔵Невозможность кастомизации. Сложно сделать свою дизайн-систему, чтобы из нее не торчали уши Material или Cupertino.

🔵Сложности для энтузиастов. Чтобы поправить баг в кнопке Material, нужно разбираться с локальной сборкой Flutter.

После разделения библиотеки 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.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2👀1
📱 Отключаем запрос о соответствии экспортным требованиям в TestFlight

Загружая новую сборку iOS-приложения, всегда приходится заходить в App Store Connect для нажатия на «Нет» в окне «Информация о соответствии экспортным требованиям».

Если ваше приложение не использует шифрование, то можно очень просто избавиться от ручного подтверждения при каждой загрузке сборки в TestFlight.

Для этого необходимо открыть файл Info.plist в папке /ios/Runner и добавить следующие строки:

<key>ITSAppUsesNonExemptEncryption</key>
<false/>


Что это дает:

🔵Больше не нужно вручную отвечать «Нет» в App Store Connect.

🔵Сборки сразу становятся доступными для тестирования в TestFlight после обработки.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3🔥2
👣 Оптимизация производительности приложений на Flutter

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


➡️ Flutter & Dart | Мобильный трудоголик
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)),
)



🔗 Читать подробнее


💡 Вывод:

Все эти виджеты решают повседневные задачи: адаптивную верстку, плавную смену контента, простые анимации и оптимизацию перерисовок. Они есть в стандартной библиотеке, не требуют подключения сторонних пакетов и при этом заметно упрощают код. Если вы до сих пор писали свои велосипеды для таких случаев - попробуйте заменить их на встроенные решения.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍2🙏1
👣 Flutter: выносим бизнес-логику из BLoC в use-cases

При разработке 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 и может использоваться с любым другим стейт-менеджером.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤1👍1
👣 Команда Flutter перевела свои сайты на Jaspr - фреймворк на Dart

Команда Flutter объявила о миграции трех основных своих сайтов (dart.dev, flutter.dev и docs.flutter.dev) на Jaspr - open-source фреймворк для создания веб-сайтов на Dart. Раньше сайты были собраны из разных технологий: документация работала на Eleventy (Node.js), а основной сайт - на Wagtail (Python + Django). Теперь все на Dart.


Почему они решили это сделать:

Старая архитектура была фрагментированной. Чтобы вносить правки или поддерживать сайты, нужно было знать Node.js, Python и Dart одновременно. Это создавало барьер для контрибьюторов и усложняло поддержку. Кроме того, добавление интерактивных элементов (например, викторин в туториалах) требовало сложных, разовых решений.


Что изменилось:

Теперь все три сайта используют единый стек на Dart. Основные изменения:

🔵Единая тулчейн. Все управляется через dart pub, dart format, dart analyze, dart test. Не нужно переключаться между разными экосистемами.

🔵Порог входа снизился. Если вы знаете Dart, вы можете вносить вклад в документацию Flutter. Никакого дополнительного обучения.

🔵Частичная гидратация. Jaspr умеет рендерить страницы как статический HTML, а потом подключать клиентскую логику только для тех компонентов, которым это нужно. Это дает быструю загрузку и хорошее SEO.

🔵Контент остался в Markdown. Рабочие процессы авторов почти не изменились. Jaspr Content поддерживает Markdown из коробки.


Почему так лучше:

🔵Flutter-разработчики чувствуют себя как дома. Компоненты Jaspr напоминают Flutter-виджеты, синтаксис похож.

🔵Современный Dart. Используются последние фичи языка: точечные шорткаты, null-aware элементы, свежие возможности JS-интеропа.

🔵Легко добавлять интерактив. Встроенная поддержка частичной гидратации позволяет без боли внедрять динамические элементы на статический сайт.

🔵Плагин анализатора. Jaspr предоставляет линтер и автодополнения прямо в IDE, как у Flutter.


🔗 Читать подробнее


💡 Вывод:

Миграция на Jaspr - пример того, как сообщество и официальная команда совместно улучшают экосистему. Единый стек на Dart упрощает поддержку, снижает порог входа для контрибьюторов и открывает возможности для более интерактивной документации. Если вы когда-нибудь хотели попробовать веб-разработку на Dart - теперь есть отличный повод.


➡️ Flutter & Dart | Мобильный трудоголик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
👣 Команда Flutter отправляется в тур по конференциям: список ивентов на 2026

Команда объявила о своем участии в десятках конференций по всему миру в 2026 году. Цель - не просто показать доклады, а лично пообщаться с разработчиками, увидеть демо вживую и собрать обратную связь. Это хорошая возможность для всех, кто давно хотел задать вопрос команде или поделиться своим мнением.


Где и когда:

В апреле стартует Google Cloud Next в Лас-Вегасе. В мае - Flutterconf в Испании, Google I/O в Саннивейле и Flutter Flow Developers Conference в Сан-Франциско. Летом команда будет в Праге, Варшаве, Берлине, Бангалоре и Орландо. Осенью - в Стокгольме, Канкуне, Берлине, Токио и других городах. Полный список обновляется на странице событий Flutter.dev.


Если вы не можете приехать - не проблема:

Многие из перечисленных конференций транслируются онлайн, а их записи потом выкладывают в открытый доступ. Это означает, что вы можете посмотреть доклады команды Flutter, не выходя из дома - прямо во время трансляции или в удобное время после. Так что даже если вашего города нет в списке, вы все равно сможете узнать обо всех новинках и важных новостях.


Почему это важно:

Flutter - это огромное сообщество. Команда говорит, что самые яркие моменты ее карьеры связаны с живым общением на ивентах. Они хотят слышать не только через баг-репорты и пул-реквесты, но и лично. Это важно для развития фреймворка.

Кроме того, участие в конференциях - способ показать, что Flutter развивается, становится все более кроссплатформенным и готов к сложным, ресурсоемким задачам.


🔗 Читать подробнее


💡 Вывод:

Если вы давно хотели встретиться с командой Flutter, задать вопрос или просто посмотреть на живые демо - теперь у вас есть такая возможность. Список конференций на 2026 год уже опубликован, и он довольно обширный. А если не можете приехать - ищите онлайн-трансляции и записи. Следите за обновлениями на сайте Flutter.dev.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🗿1
👣 Два года спустя: как увольнения повлияли на Flutter

Всем привет! Сегодня хочу разобрать интересную статью про судьбу Flutter после увольнений в Google. В апреле 2024 года Google уволил инженеров из команд Flutter, Dart и Python - за несколько недель до Google I/O, где традиционно анонсировали светлое будущее. Тогда было много паники и постов «Flutter умер». Прошло два года. Flutter не умер. Но и не остался прежним. Пора без истерик разобраться, что на самом деле изменилось.


Что тогда произошло:

Увольнения затронули в основном DevOps и инфраструктуру, а не разработчиков самого фреймворка. План развития продукта не изменился. Но сообщество правильно прочитало сигнал: для Google Flutter - больше не стратегический приоритет, а просто поддерживаемый продукт. Разница огромная. Стратегическому приоритету выделяют лучших инженеров, лоббируют внутри компании, вкладывают ресурсы. Поддерживаемому продукту - фиксят критические баги, но новых горизонтов не открывают.


Что случилось потом:

Flutter продолжил выпускать релизы. Impeller стал стабильным. Дорожная карта 2024 года выполнена. BMW, Alibaba и eBay все еще используют Flutter на проде. Опрос Stack Overflow 2024 показал 46% использования среди кроссплатформенных фреймворков - больше, чем у React Native (35%).

Но вот что важно: Тим Снит (многолетний руководитель разработки Flutter, лицо проекта на I/O) ушел в Apple в 2023 году. Брэндон ДеРозье (создатель Impeller) в 2025 году перешел в команду Android XR. Это не увольнения. Это добровольные уходы ключевых людей. И они сигнализируют о том, что даже внутри Google самые талантливые инженеры перестали видеть будущее за Flutter.


Почему я все еще использую Flutter:

Фреймворк работает. Для 90% задач кроссплатформенной разработки - стабильно, быстро, предсказуемо. Сообщество огромное, уже более 50 000 пакетов на pub.dev. Релизы выходят четыре раза в год. С точки зрения инженерной реальности Flutter не стал хуже.

Но соотношение затрат и выгод изменилось. Теперь нужно задавать себе другие вопросы.


🔗 Читать подробнее


💡 Вывод:

Используйте Flutter там, где он подходит. Понимайте свои зависимости и риски. Не принимайте архитектурные решения по звездам на GitHub и по рекомендациям от ИИ. Релевантный показатель один: решает ли фреймворк вашу проблему сегодня и есть ли у него разумный путь поддержки на три года вперед. По этому показателю Flutter проходит проверку. Не на отлично. Не так уверенно, как в 2021 году. Но проходит. Те, кто ожидает немедленного краха, ошибаются. Те, кто утверждает, что все осталось по-прежнему, тоже ошибаются. Правда, как обычно, посередине: Flutter - рабочий инструмент, но теперь его стоит выбирать с открытыми глазами, понимая, что уровень поддержки со стороны Google может и дальше снижаться.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍1👀1
👣 Как создать свое расширение для Dart DevTools

Привет! Наткнулся на статью, где автор подробно рассказывает, как добавить собственную вкладку в Dart DevTools и настроить взаимодействие с запущенным Flutter-приложением. Оказывается, это не так сложно, как кажется.


С чего начать:

Первым делом создается новый пакет под расширение. Официального шаблона нет, поэтому структуру добавляют вручную. В корне пакета создается папка devtools, внутри - build и файл конфигурации config.yaml. В конфиге указываются имя, версия, иконка для вкладки и трекер ошибок:

Файл config.yaml:

name: my_dev_tools_ext
issueTracker: https://...
version: 0.0.1
materialIconCodePoint: '0xe0b1'
requiresConnection: false


Для работы расширения нужен пакет devtools_extensions. Он дает доступ к менеджерам: extensionManager (взаимодействие с DevTools), serviceManager (доступ к VM-сервису) и dtdManager (связь с Dart Tooling Daemon).


Интерфейс и тестирование:

Сами виджеты можно собирать из готовых компонентов пакета devtools_app_shared. Например DevToolsButton уже имеет стиль, подходящий для интерфейса DevTools, а через extensionManager.showNotification можно показывать уведомления.

Для отладки расширения используется симулированная среда:

flutter run -d chrome --dart-define=use_simulated_environment=true


Перед публикацией сборка создается командой build_and_copy, а проверить корректность структуры можно через validate.


Два типа расширений:

🔵Standalone extensions - отдельные пакеты, не привязанные к существующему pub-пакету. Подходят для инструментов, которые могут пригодиться в любом проекте.

🔵Companion extensions - поставляются вместе с существующим pub-пакетом. Когда пользователь подключает такой пакет, расширение автоматически появляется в DevTools. Для этого в корне пакета достаточно добавить папку extension/devtools со сборкой и конфигом.


🔗 Читать подробнее


💡 Вывод:

Расширения DevTools открывают интересные возможности для создания инструментов отладки, визуализации состояния и даже управления приложением в рантайме. Статья дает хороший практический старт: от создания пакета до выполнения произвольного Dart-кода на живом приложении. Если вы когда-нибудь хотели добавить свою вкладку в DevTools - это вполне реально.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2🙏1
👣 Улучшаем локальный поиск на Dart и Flutter

Обычный строковый поиск работает только при точном совпадении. Одна лишняя буква, опечатка или другой падеж и результат пустой. В этой статье автор разбирает, как реализовать локальный поиск, который понимает, что пользователь имел в виду, даже если ввел с ошибкой.


Почему простое вхождение не работает:

Пользователи часто ошибаются. Вместо «Арбатская» пишут «Орбатская», вместо «Петровка» - «Питровка». Простой поиск по вхождению подстроки такие запросы игнорирует. А отправлять каждый запрос на сервер - долго и не всегда возможно.


Что такое расстояние Левенштейна:

Это число, которое показывает, сколько операций нужно, чтобы превратить одну строку в другую. Операции - вставка, удаление, замена символа. Например, «кот» -> «код»: одна замена символа, расстояние = 1. «Австрия» -> «Австралия»: нужно добавить две буквы, расстояние = 2.

Для поиска удобнее использовать нормализованное значение от 0 до 1, где 0 - полное совпадение, 1 - строки разные.


Более точный вариант - расстояние Дамерау‑Левенштейна:

Оно добавляет еще одну операцию - перестановку соседних символов. Это одна из самых частых опечаток: «годки» вместо «годик». Обычное расстояние Левенштейна даст 2, а расстояние Дамерау‑Левенштейна - 1, потому что достаточно переставить буквы.


Как это реализовать во Flutter:

Автор приводит пример поиска по адресам и станциям метро. Алгоритм:

🔵Привести строки к нижнему регистру.

🔵Вычислить расстояние Дамерау‑Левенштейна между поисковым запросом и каждым элементом списка.

🔵Добавить к адресу название метро, если оно есть.

🔵Отсортировать результаты по близости (чем меньше расстояние, тем выше результат).

🔵Отфильтровать только те, где расстояние меньше заданного порога (например, 0.5).


🔗 Читать подробнее


💡 Вывод:

Такой поиск имеет смысл не везде. В идеале - отдать поиск на бэкенд, если он это умеет. Если нет и приходится искать локально, расстояние Дамерау-Левенштейна может спасти ситуацию. Но не ждите чудес: алгоритм требовательный к ресурсам, а порог совпадения придется подбирать вручную.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤1🔥1
👣 Flutter отказывается от CocoaPods в пользу Swift Package Manager

Начиная с релиза Flutter 3.44, Swift Package Manager (SPM) заменяет CocoaPods как стандартный менеджер зависимостей для iOS и macOS. Это означает, что больше не нужно возиться с установкой Ruby или настройкой CocoaPods, чтобы просто запустить приложение.


Почему CocoaPods уходит:

CocoaPods официально переведен в режим поддержки без активного развития. Его реестр станет доступен только для чтения 2 декабря 2026 года. Существующие сборки продолжат работать, но новые версии пакетов добавляться уже не будут. Flutter переходит на решение, которое официально поддерживает Apple, чтобы приложения продолжали получать обновления зависимостей и имели доступ к экосистеме Swift-пакетов.


Что будет с приложениями:

Flutter CLI автоматизирует переход. При сборке или запуске iOS / macOS приложения CLI сам обновит Xcode-проект для использования SPM. Если приложение использует плагины, которые еще не перешли на SPM, Flutter выдаст предупреждение и временно использует CocoaPods для таких плагинов.

В случае критических проблем можно временно отключить SPM в pubspec.yaml:

flutter:
config:
enable-swift-package-manager: false


Но компания просит сообщать о таких проблемах, чтобы успеть их исправить до полного удаления CocoaPods.


🔗 Читать подробнее


💡 Вывод:

Переход на SPM - неизбежный шаг. CocoaPods устарел, и поддержка его заканчивается. Для разработчиков приложений процесс в основном автоматический. А вот авторам плагинов предстоит работа - иначе их пакеты станут несовместимыми и потеряют позиции на pub.dev. Лучше заняться этим сейчас, а не ждать, когда CocoaPods окончательно отключат.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2❤1
👣 Agent Skills для Flutter и Dart: готовые инструкции для типовых задач

Команда Flutter представила Agent Skills - специальные инструкции, которые делают ИИ-ассистентов более компетентными в разработке на Flutter и Dart. Это не просто документация, а готовые сценарии для типовых задач: локализация, адаптивная верстка, интеграционные тесты, использование новых возможностей языка.


Зачем это нужно:

ИИ-агенты хороши в общих вопросах, но для профессиональной Flutter-разработки этого мало. Нужно понимать нюансы локализации, правильно применять свежие фичи Dart, настраивать интеграционные тесты. Skills закрывают этот пробел.

Важное отличие от MCP: Model Context Protocol дает агентам инструменты (молоток и гвозди), а Skills учат, как этими инструментами пользоваться (чертеж и навыки строителя). Skills также экономят токены благодаря «прогрессивному раскрытию» - агент подгружает инструкции только тогда, когда они действительно нужны.


От теории к практике:

Ранние эксперименты показали: Skills, которые просто дают документацию, не так полезны. Документация Flutter и так открыта и современные модели неплохо умеют находить нужную информацию. Поэтому команда сделала Skills задаче-ориентированными - они учат агента выполнять конкретные действия.


Что уже доступно:

Примеры Skills из открытых репозиториев:

🔵flutter-add-integration-test - настраивает Flutter Driver и превращает MCP-действия в постоянные интеграционные тесты.

🔵flutter-setup-localization - добавляет поддержку локализации в проект.

🔵flutter-build-responsive-layout - создает адаптивный макет через LayoutBuilder, MediaQuery или Expanded/Flexible.

🔵dart-use-pattern-matching - рефакторит код с использованием pattern matching из Dart.

🔵dart-collect-coverage - собирает покрытие тестами и генерирует LCOV-отчет.


🔗 Читать подробнее


💡 Вывод:

Agent Skills - шаг к тому, чтобы ИИ-ассистенты перестали быть просто умными поисковиками и стали реальными помощниками в конкретных задачах. Пока доступен базовый набор, но команда обещает расширять его вместе с сообществом. Agent Skills не превратят ИИ в сеньора, но избавят от необходимости каждый раз объяснять, как настроить локализацию или собрать покрытие тестами.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥2🙏1
👣 yx_navigation: декларативная навигация во Flutter

Привет! Наткнулся на интересную статью, где разработчики из Яндекса рассказывают, как они создали свой пакет для навигации во Flutter. Проблема знакомая: проект растет, появляются табы, вложенные модули, диплинки, а стандартные решения перестают работать. В итоге они написали свое решение и поделились им со всеми.


В чем суть:

Основная идея yx_navigation в том, что состояние навигации - это не стек, а дерево узлов RouteNode. Каждый узел содержит маршрут, параметры и список дочерних узлов. Все просто: добавил узел - экран появился, убрал - исчез.


Какую проблему решает:

🔵Мутация неактивных ветвей. Ключевая фича. Пользователь во вкладке «Сообщения», а в это время прилетает заказ. Его нужно добавить во вкладку «Заказы», но без переключения на нее. В go_router это невозможно - любой переход переключает вкладку. В yx_navigation можно получить контроллер, привязанный к неактивной ветке, и выполнить push из бизнес-логики.

🔵Управление навигацией без BuildContext. Большинство пакетов требуют context для переходов. Интерактор, обрабатывающий push-уведомление, контекста не имеет. В yx_navigation можно создать менеджер состояния заранее и управлять навигацией откуда угодно.

🔵Изоляция фич. Фича подключается одной строкой. Хост не знает о внутренних маршрутах фичи, фича - о хосте. Команды могут работать независимо.

🔵Совместимость с легаси-кодом. Старый код на Navigator.push(), showDialog() продолжает работать. Compatibility Layer адаптирует вызовы к новой модели.

🔵Дружелюбие к разработчику. Встроенная debug-панель показывает дерево состояния в реальном времени, историю мутаций и сериализованное состояние в URL.


🔗 Читать подробнее


💡 Вывод:

yx_navigation - не очередная обертка над Navigator 2.0, а решение, выросшее из реальных проблем крупного проекта. Пакет подойдет тем, кто уперся в ограничения go_router, кому надоело ждать кодогенерацию в auto_route и кто хочет управлять навигацией без привязки к UI и менять состояние даже в неактивных вкладках.


Подписаться на канал:
➡️ Flutter & Dart | Мобильный трудоголик

Закрытый канал:
🚀 Мобильный трудоголик PRO
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2👍1