TGViewer
Channel Public Channel
Flutter & Dart | Мобильный трудоголик

Flutter & Dart | Мобильный трудоголик

@hardworkerflutter

Пишу простым языком про разработку на Flutter & Dart (iOS, Android, macOS, Windows) и мобильную разработку в целом.
Обо мне: https://t.me/hardworkerFlutter/2
Чат: @flutterDevChat
Другие мои каналы: @hardworkerIT и @itDenisov
Subscribers
405
Photos
29
Videos
1
Links
82

Showing posts older than #52 · Back to latest

Older Posts 20 shown
Post #51 926
👣 Убираем хардкод и лишние перерисовки с помощью стандартных виджетов

В повседневной разработке часто встречаются задачи, которые можно решить красиво и без лишнего кода. Вместо того чтобы городить велосипеды, достаточно знать несколько встроенных инструментов 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 | Мобильный трудоголик
  • ❤ 2
  • 👍 2
  • 🙏 1
Post #50 847
👣 Оптимизация производительности приложений на 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 | Мобильный трудоголик
  • 👍 3
  • 🔥 2
  • ❤ 1
  • 🙏 1
Post #49 686
📱 Отключаем запрос о соответствии экспортным требованиям в TestFlight

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

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

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

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


Что это дает:

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

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


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 4
  • ❤ 3
  • 🔥 2
Post #48 798
👣 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 | Мобильный трудоголик
  • 👍 4
  • 🔥 2
  • 👀 1
Post #47 1.91K
👣 Как удалить все неиспользуемые импорты во 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 | Мобильный трудоголик
  • 👍 5
  • ❤ 1
Post #46 1.93K
👣 Как Dart и Flutter смотрят на ИИ в 2026 году

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


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

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


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

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

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

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

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

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


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


💡 Вывод:

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


➡️ Flutter & Dart | Мобильный трудоголик
  • ❤ 2
  • 👍 1
  • 🙏 1
  • 👀 1
Post #45 586
👣 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 | Мобильный трудоголик
  • 👍 6
  • ❤ 2
  • 🔥 1
Post #44 586
👣 Что важно знать о 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 | Мобильный трудоголик
  • 👍 3
  • ❤ 2
  • 🔥 1
Post #43 781
👣 Когда в 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 | Мобильный трудоголик
  • 👍 5
  • 🔥 2
  • ❤ 1
Post #42 2.26K
🏋️ Установка 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 | Мобильный трудоголик
  • 👀 4
  • 🙏 2
  • 👍 1
  • 🗿 1
Post #41 723
👣 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 | Мобильный трудоголик
  • 👍 4
  • 🔥 2
  • ❤ 1
Post #40 612
👣 Keys во Flutter: как не потерять состояние при перестройке списков

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


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

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

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


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

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

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

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

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


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

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

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

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


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

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

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

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


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

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


💡 Вывод:

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


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 3
  • ❤ 1
Post #39 649
👣 Как добавить эффект Liquid Glass в Flutter-приложение

С выходом iOS 26 компания Apple представила дизайн Liquid Glass - ту самую жидкую стеклянную эстетику, которая делает интерфейсы объемными и тактильно приятными. Сообщество Flutter все это время искало способ повторить это на своей платформе. Попытки были, но с ограничениями: кто-то завязывался на Impeller и терял поддержку Windows и Web, кто-то просто делал обычное размытие, выдавая его за жидкое стекло. Теперь появилось работающее кроссплатформенное решение.


Что раньше:

Краткий обзор того, что предлагалось раньше:

🔵Пакеты, которые либо не работали, либо не имели примеров.

🔵Решения, завязанные на Impeller - красиво, но только для мобилок.

🔵Обычный стекломорфизм с размытием, который никакой не жидкий.

🔵Нативные обертки, которые работали только на iOS.

Все они либо не были кроссплатформенными, либо не давали нужного эффекта.


Что появилось сейчас:

Пакет liquid_glass_easy делает именно то, что заявлено: настоящие интерактивные линзы из жидкого стекла с физикой преломления, искажения и реакции на касания. Работает на Android, iOS, Web, macOS и Windows. В основе - GPU-шейдеры, так что производительность остается высокой даже при нескольких активных линзах.


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

Все строится вокруг двух виджетов:

🔵LiquidGlassView - контейнер, который захватывает содержимое фона в реальном времени и передает его в линзы.

🔵LiquidGlass - сама линза, которую можно настроить: форма, размер, степень искажения, размытие, цвет, направление света.

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


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


💡 Вывод:

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


➡️ Flutter & Dart | Мобильный трудоголик
  • 🔥 4
  • ❤ 1
  • 👍 1
Post #38 1.77K
👣 Анонсирован Genkit для Dart: фреймворк для ИИ-приложений

Google анонсировала Genkit Dart - open-source фреймворк для создания полноценных ИИ-приложений на Dart и Flutter. Это не просто очередная обертка над API, а инструмент, который позволяет строить сложные ИИ-сценарии с типизацией, тестированием и удобным UI для отладки. Пока в предварительной версии, но уже выглядит многообещающе.


Что такое Genkit Dart и зачем он нужен:

Сейчас ИИ-функции проникают повсюду: кто-то строит вокруг них новые продукты, кто-то добавляет умные фичи в существующие. Genkit Dart закрывает сразу несколько потребностей:

🔵Единый API для работы с разными моделями (Google Gemini, OpenAI, Anthropic и другие совместимые).

🔵Строгая типизация ответов - никаких неожиданных форматов.

🔵Возможность писать логику один раз и запускать ее где угодно: на сервере, в облаке или прямо внутри Flutter-приложения.

🔵Удобный локальный UI для тестирования и отладки промптов.


Как это работает:

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


Все внутри Flutter (для прототипов):

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


Бэкенд + Flutter с общей типизацией:

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


Прокси-сервер для моделей:

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


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


💡 Вывод:

Genkit Dart - это попытка внести порядок в хаос ИИ-разработки. Вместо того чтобы каждый раз городить свои обертки над моделями, можно взять готовый фреймворк с типизацией, тестируемостью и удобным UI. Пока это превью, но направление выглядит правильным. Если вы работаете с Dart/Flutter и думаете, как добавить в проект ИИ-фичи - присмотритесь.


➡️ Flutter & Dart | Мобильный трудоголик
  • 🔥 4
  • 👍 1
Post #37 546
👣 Обновлен плагин Flutter для VS Code: что нового?

Вышла новая версия плагина для VS Code, и в ней снова доработали то, что бесит больше всего - скорость, тесты и повседневные мелочи. Никаких революций, но десяток мелких улучшений, которые в сумме делают работу заметно комфортнее.


Тесты теперь работают адекватно:

В этом обновлении тестам уделили особое внимание. Исправили несколько раздражающих багов: тесты больше не выдают ошибку Cannot read properties of null в консоли, не пропадают из панели результатов и не помечаются ошибочно как пропущенные.

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

Для тех, кто использует test_reflective_loader, тесты теперь группируются по классам - навигация по результатам становится чище.


Параллельные действия:

Команда Get Packages for All Projects теперь умеет запускать несколько процессов одновременно. Раньше пакеты подтягивались последовательно для каждого проекта, что могло затягиваться. Теперь все летает параллельно, используя до половины ядер процессора.


Редактор и навигация:

Несколько мелочей, которые важны в ежедневной работе:

🔵Переход к импорту больше не прыгает в другую вкладку, если файл уже открыт - остается там, где удобно.

🔵Исправления для зависимостей теперь корректно перемещают их из dev_dependencies в dependencies, если это нужно.

🔵Подсветка ключевых слов стала единообразной - разница между начальной и семантической подсветкой ушла.

🔵Обновили грамматику для грядущих Primary Constructors - готовимся к новым фичам Dart.

🔵Геттеры и поля теперь отображаются точнее, без путаницы.


Работа с эмуляторами:

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


Совместимость и старые версии:

Поддержка SDK ниже Dart 3.2 / Flutter 3.16 окончательно прекращена. Если вы все еще сидите на древних версиях, придется либо обновляться, либо откатывать плагин до старой версии - на сайте есть таблица совместимости.


Что будет в будущих SDK:

Некоторые фичи уже есть в бета-версиях, но в стабильных появятся позже:

🔵Стек-трейсы теперь показываются в всплывающих окнах, даже если ошибка проброшена через Completer.completeError().

🔵Фабричные конструкторы больше не отображаются как <unknown> в навигации.


🔗 Ссылка на плагин


💡 Вывод:

Очередное обновление, которое не кричит о себе, но делает работу с Flutter в VS Code чуть более предсказуемой и быстрой. Особенно радуют правки тестов и параллельные операции. Если вы активно используете VS Code для разработки - обновляйтесь, мелочи действительно имеют значение.


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 4
  • ❤ 1
Post #36 498
👣 Почему Flutter-приложение греет смартфон и как это исправить

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


Слишком частые перестройки виджетов:

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

Что делать: дробить UI на мелкие виджеты, использовать const где возможно, подключать умное управление состоянием (Riverpod, Bloc), чтобы обновлялись только те части экрана, которым это действительно нужно.


Анимации, которые не знают отдыха:

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

Решение: всегда останавливать анимации в dispose, при возможности приостанавливать их, когда виджет не в фокусе, и не злоупотреблять тяжелыми Lottie-файлами там, где можно обойтись простыми переходами.


Сетевые запросы, которые грузят сервер без продыху:

Каждый запрос к сети - это пробуждение радио-модуля, парсинг JSON, обновление UI. Если приложение опрашивает сервер каждые пару секунд, телефон будет греться даже в фоне. Особенно больно, когда запросы делаются прямо в build или без кэширования.

Выход: выносить сеть из build, использовать кэширование, реже опрашивать сервер, а для real-time фич переходить на WebSockets, которые работают эффективнее частых REST-запросов.


Тяжелые изображения и видео:

Загрузить картинку в полном разрешении и отобразить ее как есть - легко. Но GPU придется каждый раз масштабировать этот гигантский файл, тратя на это ресурсы. Если таких картинок в списке много - телефон начнет нагреваться очень быстро.

Исправление: изменять размер изображений на лету (cacheWidth, cacheHeight), сжимать, использовать отложенную загрузку и не запускать видео автоматически в каждом элементе списка.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 2
  • ❤ 1
  • 🔥 1
Post #35 497
👣 Настройка окружений во Flutter приложении с помощью Flavors

Когда приложение выходит за пределы пет-проекта, возникает необходимость держать окружения раздельно. Dev, Staging и Production должны жить своей жизнью: с разными API-ключами, бэкендом, а иногда даже иконками и названиями. В Flutter эта задача решается через Flavors. Рассказываю, как настроить и не запутаться.


Что такое Flavors и зачем они нужны:

Flavors (или схемы в iOS, продуктные варианты в Android) позволяют из одной кодовой базы собирать разные варианты приложения. У каждого варианта могут быть свои:

🔵URL бэкенда и ключи API.

🔵Имя приложения и bundle ID.

🔵Иконки и сплеш-скрины.

🔵Настройки сборки и зависимости.

Это дает возможность установить на устройство одновременно dev-версию и продовую, не боясь, что они перезатрут друг друга. И главное - исключает случайную отправку тестового кода в релиз.


Организация кода:

Самый простой способ - сделать отдельные точки входа для каждого окружения. В папке lib создаем файлы:

🔵main_dev.dart

🔵main_staging.dart

🔵main_prod.dart

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


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

🔵com.example.app.dev

🔵com.example.app.staging

🔵com.example.app

В 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"


Запускаем и получаем разные иконки для каждого окружения.


Лучшие практики:

🔵Не храните ключи и секреты прямо в коде. Используйте .env файлы или безопасное хранилище.

🔵Ведите имена flavors одинаково на Android и iOS - меньше путаницы.

🔵Настройте CI/CD так, чтобы пайплайны собирали каждый flavor отдельно.

🔵Для тестировщиков dev-сборка должна визуально отличаться (иконка, цвет темы), чтобы случайно не перепутали с продакшеном.


🔗 Ссылка на подробную статью


💡 Вывод:

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


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 3
  • ❤ 1
Post #34 488
👣 Дорожная карта Flutter и Dart: что изменится в 2026 году

Всем привет! Команда 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 пытаются сделать полноценным языком для бэкенда, а инструменты разработки более умными и интегрированными с ИИ. Если хотя бы половина этого выстрелит, экосистема ждет серьезный апгрейд.


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 3
  • ❤ 1
  • 🔥 1
Post #33 505
👣 Async/await и Isolate в Flutter: не путайте ожидание с работой

Когда приложение тормозит, первая мысль: «нужно вынести это в отдельный поток». В 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.

🔵Нужно один раз обработать большой кусок данных? compute().

🔵Есть долгий фоновый процесс с обменом сообщениями? Raw Isolate.

🔵Пытаетесь ускорить вычисления, просто добавив async? Бесполезно, почитайте заново.


💡 Вывод:

Async/await и Isolate не конкуренты, а партнеры. Первый отвечает за ожидание, второй - за параллельное выполнение. Смешивать их нужно осознанно, а не по принципу «чтоб не тормозило». Иначе вместо плавного интерфейса получите или вечно грузящийся процессор, или кучу мертвого кода, который ничего не ускоряет.


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 4
  • 🔥 1
Post #32 431
👣 Как оживить интерфейс с помощью встроенных возможностей Flutter

Всем привет! Пользовательский опыт складывается из мелочей. То, как элемент реагирует на касание, насколько плавно происходит удаление, появляется ли подсказка в нужный момент - все это формирует ощущение качественного приложения. Flutter предоставляет готовые инструменты для таких сценариев и о них полезно знать не только новичкам.


Подсказки, которые не раздражают:

Tooltip - идеальный способ объяснить действие без захламления интерфейса. На мобильных устройствах подсказка появляется при долгом нажатии, на десктопе - при наведении.

Tooltip(
message: 'Очистить корзину',
child: IconButton(
icon: Icon(Icons.delete_sweep),
onPressed: _clearCart,
),
)


Это особенно актуально для иконок, значение которых не всегда очевидно. Но злоупотреблять не стоит: если каждая кнопка обзаведется подсказкой, пользователь перестанет их замечать.


Когда удаление становится действием:

Свайп для удаления давно стал стандартом мобильных интерфейсов. Вместо кнопок и лишних подтверждений - простое движение пальцем. Dismissible реализует это буквально в несколько строк.

Dismissible(
key: Key(todo.id),
background: Container(color: Colors.red),
onDismissed: (_) => _deleteTodo(todo.id),
child: ListTile(title: Text(todo.title)),
)


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


Перетаскивание как способ организации:

Draggable и DragTarget открывают возможности для создания интерфейсов, где пользователь сам управляет расположением элементов.

Draggable<int>(
data: itemIndex,
feedback: Material(child: Container(width: 50, height: 50, color: Colors.blue)),
child: Container(width: 50, height: 50, color: Colors.grey),
childWhenDragging: Container(width: 50, height: 50, color: Colors.grey[300]),
)


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


Списки, которые можно перестраивать:

ReorderableListView решает задачу, которая раньше требовала танцев с бубном: изменение порядка элементов простым перетаскиванием.

ReorderableListView(
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) newIndex--;
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
});
},
children: [
for (int i = 0; i < items.length; i++)
ListTile(
key: ValueKey(items[i]),
title: Text(items[i]),
),
],
)


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


💡 Вывод:

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

Хороший интерфейс не кричит о себе. Он просто работает так, как ожидает пользователь. Dismissible, Tooltip, Draggable и ReorderableListView помогают приблизиться к этому идеалу без изобретения велосипеда. Но любой инструмент требует меры и понимания контекста.


➡️ Flutter & Dart | Мобильный трудоголик
  • 👍 2
  • 🔥 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →