Flutter. Много
Відкрити в Telegram
Заказать мобильную разработку: https://amiga.ru//?utm_source=tg Заказать рекламу в канале @amiga_agency_bot Новости Flutter-разработки, дайджесты мероприятий, личный опыт.
Показати більше3 023
Підписники
-1324 години
-247 днів
-6430 день
Архів дописів
3 019
Hola Amigos! Собрали в одну подборку все полезные посты июня, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
🟡Snippet для анимированного виджета
🟡Форматируем код при сохранении
🟡Кастомные иконки для iOS
🟡Оптимизируем Assets. Часть 1. Часть 2. Часть 3.
🔴Динамические иконки приложения на Flutter
Всем хорошего кода!
3 019
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead агентства продуктовой разработки Amiga. Сегодня мы снова поговорим про иконки приложения, но в этот раз про динамические, которые вы можете менять по воздуху или дать возможность пользователю выбрать самому. Про это мы нашли и перевели для вас подробную инструкцию.
Что вы сможете узнать из нее:
• Как добавить сразу несколько вариантов иконок в ваше приложение для iOS и Android;
• Как одновременно предоставить выбор пользователю для изменения настроек приложения и иногда самим их перезаписывать по воздуху;
🔗 Ссылка на переведенную статью
Делитесь в комментариях, пробовали ли вы менять иконку приложения таким способом?
3 019
Hola, Amigos! Завершаем цикл постов про оптимизацию ассетов. Сегодня посмотрим на фишку, которая появилась в Flutter 3.41 - платформенные ассеты.
Раньше мы писали пути к нашим ассетам в
pubspec.yaml так:
assets:
- assets/images/
- assets/android/icons/
- assets/ios/icons/
- assets/web/icons/
- assets/desktop/icons/
Тут ассеты для всех платформ летят во все сборки, даже в те, где они не нужны. Теперь Flutter позволяет выделить отдельные ассеты как под одну, так и под несколько платформ. Например, какие-то папки нам нужно открыть только для десктопных приложений:
assets:
- assets/images/
- path: assets/desktop/icons/
platforms:
- windows
- linux
- macos
- path: assets/android/icons/
platforms:
- android
- path: assets/ios/icons/
platforms:
- ios
- path: assets/web/icons/
platforms:
- web
Этот новый способ не будет добавлять ассеты для других платформ в сборку, что сделает ее меньше и легче.
Рассказывайте в комментариях, знали ли о таком?3 019
Hola, Amigos! В прошлой части мы рассказали, какими лайфхаками пользуемся, чтобы наши ассеты были меньшего размера. Сегодня поговорим про то, как нам сформировать растровые изображения так, чтобы они хорошо смотрелись на любом устройстве.
Во-первых, у каждого устройства есть соотношение размера экрана к его разрешению. Его можно измерить в виде DPI (dot per inch, точки на дюйм), так и в специальном соотношении, где при единице одна точка будет равна одному физическому пикселю. Из Flutter мы его можем получить через
MediaQuery.devicePixelRatioOf(context).
Во-вторых, важно помнить, что Flutter отрисовывает именно по точкам, а не по пикселям. Поэтому, если у нашего изображения есть предел на экране, то этот предел и будет его максимальным размером.
Теперь, когда у нас определены размеры в точках, то нужно подготовить изображения. В прошлом посте мы писали, что максимальный - это размер, умноженный на 4. Но на самом деле мы готовим много одинаковых изображений - под devicePixelRatio со значениями 1x, 1.5x, 2x, 3x и 4x. Конечно, вы можете сделать и больше, но практика показывает, что этих размеров более, чем достаточно.
Далее важно их правильно хранить. Для этого в папке для ассетов нужно создать еще несколько - для всех соотношений, кроме самого маленького. Называем их мы таким образом: x{N} - где N - это 1.5, 2.0 и т. п. Наша структура будет выглядеть так:
assets/ —| images/ ——| x1.5/ ———| image.webp ——| x2.0/ ———| image.webp ——| x3.0/ ———| image.webp ——| x4.0/ ———| image.webp —| image.webpВ
pubspec.yaml мы добавляем только корневую папку и используем только самый маленький файл, так как Flutter уже самостоятельно будет обрабатывать эти значения.
В следующей части мы расскажем, как работать с ассетами под определенные платформы. Пишите в комментариях, пользуетесь ли вы таким разделением?3 019
Hola, Amigos! Среднестатистический пользователь любит, когда скачивание приложения занимает мало времени. Для этого нам нужно по максимуму уменьшать размер установочного файла. В основном это необходимо для Android, но может быть полезно и под другие платформы. И главное, чтобы это быстро и правильно работало.
В первую очередь много места занимают ассеты: картинки, шрифты, иконки. Держите несколько полезных лайфхаков от нас:
1️⃣ Храните растровые изображения в формате WebP. Это современный формат, который создан в недрах Google и он намного эффективнее сжимает файлы, чем более распространенные JPEG и PNG, а также умеет в прозрачность.
2️⃣ Следите за максимальным размером изображений. Если вам нужно отобразить картинку в формате 100 на 100, а вы добавляете в ассеты картинку размером 2000 на 2000, то это излишне даже для очень больших экранов. Поэтому, максимальный размер мы высчитываем так - размер виджета, умноженный на 4.
3️⃣ Храните иконки в шрифте. Для хранения этого типа ассетов существует три варианта:
• Хранить иконки в формате SVG. Да, это векторный формат, но он не до конца подходит к Flutter. Мало того, что для него необходима отдельная библиотека, так еще ее использование съедает ресурсы.
• Перевод иконок в специальный векторный формат. Это лучше, но не лишает всех минусов, так как такие иконки все равно отдельные и тоже влияют на отрисовку, хоть и меньше.
• Специализированный шрифт. Это нативный вариант, так как вы получаете
IconData, а при сборке будут откидываться неиспользуемые иконки. Но есть минусы - не всегда получается сложные иконки перегнать в этот формат и он подходит только для монохромных иконок.
Поэтому мы на своих проектах стараемся использовать второй и третий вариант, хотя большее предпочтение отдаем как раз шрифту.
В следующей части мы расскажем, как подогнать растровые изображения под разрешение экрана устройства. А пока делитесь в комментариях, какие еще лайфхаки используете для ассетов?3 019
+5
Hola, Amigos! Мы уже рассказывали про то, как сделать динамические иконки приложения на iOS, но с того времени появился Liquid Glass, а вместе с ним вышел дополнительный инструмент - Icon Composer.
Он умеет:
• Делить иконки на слои, чтобы правильно организовывать все эффекты
• Показывать сетку, чтобы расположить элементы на нужное место. Сама сетка может быть как темной, так и светлой
• Показывать иконку в светлой и темной темах, а также в монохроме, и где все Liquid Glass слои становятся прозрачными. Фон, на котором смотреть, тоже можно менять - есть серый и цветной
• Менять направление света так, как будто пользователь поворачивает телефон
• Экспортировать все иконки как PNG
В итоге работы мы получим файл с расширением
.icon. Теперь его можно добавить в Xcode, где нужно выбрать название нашей иконки. Очень важно - оставить иконки для более старых версий iOS, так как такой формат поддерживается только от iOS 26.
Рассказывайте в комментариях, пользовались ли уже этим инструментом?3 019
Hola, Amigos! Все мы используем IDE для разработки и это облегчает нам написание кода. Но IDE не умеет автоматически применять форматирование написанного. Давайте вместе разберемся как это делать при сохранении файла.
Для Android Studio перейдем в настройки IDE (Settings на Windows и Linux, Preferences на macOS), там в “Languages & Frameworks” и выберем Flutter. У нас откроется окно настроек плагина, где нужно включить чекбокс “Format code on save”.
Для VS Code все немного проще. В файл с настройками нужно всего лишь включить строку:
editor.formatOnSave = true
Делитесь в комментариях, помогает ли автоматическое форматирование кода на вашем проекте? Или вы делаете это вручную?3 019
Hola, Amigos! Продолжаем рассказывать про полезные сниппеты. Сегодня создадим сниппет с настройкой для анимации через Animated Controller -
animStful.
class $NAME$ extends StatefulWidget {
const $NAME$(super.key);
@override
State<$NAME$> createState() => _$NAME$State();
}
class _$NAME$State extends State<$NAME$> with SingleTickerProviderMixin {
late final AnimationController _controller;
late final Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: $DURATION$),
);
_controller.addListener(() => setState(() {}));
_animation = Tween<double>(begin: 0, end: 1).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Container();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Можно копировать в свой IDE и пользоваться!
#snippets@flutter_amiga3 019
Hola, Amigos! Собрали в одну подборку все посты мая, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
🟡 Прокачиваем локальный поиск на Dart и Flutter
🟡 Полезные сниппеты для жизненного цикла виджета
🟡 Полезные extensions для DateTime
🟡 Как понять, нужна ли библиотека и как ее выбрать?
🟡 Обзор плагина Flutter Intl для IDE
🟡 Краткий обзор Dart 3.12 и Flutter 3.44
🟡 Оптимизируем кастомные анимации
Всем хорошего кода!
P.S. Завтра ждем вас на квартирнике “Мифическая кроссплатформа” на CodeFest в Новосибирске!
3 019
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня разберем два виджета, которые помогают оптимизировать производительность анимаций -
AnimationBuilder и TickerMode.
Начнем с AnimationBuilder. Он перерисовывает только изменяющиеся части, не затрагивая остальное. Не требует addListener у AnimationController. Идеален для анимации фона без перерисовки всего виджета..
AnimatedBuilder(
animation: _controller,
child: Container(
width: 200.0,
height: 200.0,
color: Colors.green,
child: const Center(child: Text('Whee!')),
),
builder: (BuildContext context, Widget? child) {
return Transform.rotate(
angle: _controller.value * 2.0 * math.pi,
child: child,
);
},
),
TickerMode позволяет управлять активностью анимаций у дочерних виджетов. Он полезен для остановки анимаций, когда пользователь переходит на другой экран, сворачивает приложение или выключает экран устройства. Это все можно реализовать вместе с использованием AppLifecycleState, про который мы рассказывали ранее.
Работает это просто. Где-то сверху оборачиваем наш экран в TickerMode и передаем ему переменную в свойство enabled. Но работать будет, только если контроллеры анимаций завязаны на TickerProviderStateMixin и SingleTickerProviderStateMixin.
TickerMode(
enabled: _enabled,
child: ...
);
Делитесь в комментариях, используете ли данные виджеты у себя на проектах?3 019
Hola, Amigos! В рамках Google I/O 2026 были представлены Dart 3.12 и Flutter 3.44. Давайте вместе разберемся, что в них нового.
Начнем, конечно же, с Dart. Тут добавился новый функционал - приватные именованные параметры. Теперь мы можем добавлять наши приватные переменные в конструктор.
Как это было в старых версиях:
class MyClass {
final String _myVar;
const MyClass({required String myVar}) : _myVar = myVar;
}
Как это выглядит теперь:
class MyClass {
final String _myVar;
const MyClass({required this.myVar});
}
А при использовании ничего не поменялось:
final a = MyClass(myVar: ‘my value’);
Еще из того, что добавилось:
🟡В экспериментальной фазе находятся обновленные конструкторы для классов;
🟡Добавилась нативная поддержка Git LFS;
🟡Запустили превью Genkit Dart.
Flutter 3.44 приносит нам 2 больших и важных изменения, для которых нужно будет проводить миграции, если этого еще не сделано:
🔴Повышение версии Android Gradle Plugin до версии 9.0 и переход на использование Kotlin. Пока временно есть обратная совместимость.
🔴Переезд на Swift Package Manager, который очень ждали.
Еще изменения в фреймворке:
🟡Переработана система обнаружения Widget Preview, что уменьшило потребление памяти;
🟡Добавлена поддержка Apple Silicon для macOS приложений без необходимости использования Rosetta;
🟡Для Android добавлен Hybrid Composition++ для отрисовки нативных виджетов, который производительнее обычного Hybrid Composition;
🟡Много других, более мелких изменений.
Делитесь в комментариях, как вам обновление и смотрели ли Google I/O 2026?
3 019
+4
Hola, Amigos! Продолжаем рассказывать вам о полезных плагинах для Android Studio и VS Code. Сегодня на очереди плагин, который заменит нам ручное использование CLI-инструмента - Flutter Intl. Он позволяет автоматизировать нашу работу с i18n.
Делитесь в комментариях, что лучше, плагин или CLI?
#плагины
3 019
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Для многих задач уже есть готовые библиотеки, но иногда нужно удостовериться, а действительно ли та или иная библиотека нужна в разрабатываемом приложении? Ловите наш чек-лист по выбору библиотек и проверке необходимости их применения.
Начнем с того, что нужно определиться, на самом ли деле нужна библиотека. Если это библиотека какого-то сервиса, причем официальная, то ее можно добавлять. Но для других случаев зададим себе несколько вопросов:
⚪️Сколько времени в будущем сэкономит использование библиотеки?
⚪️Насколько сложно будет написать такой функционал своими силами?
⚪️Есть ли у команды опыт для реализации такого функционала?
Если библиотека будет реально экономить время разработчиков, требуемый функционал достаточно сложен или у команды нет необходимого опыта для его реализации - будем выбирать и искать пакет.
Если вы уже знаете саму библиотеку и использовали ее, то берите. Если еще нет или вы в первый раз ищите под такой функционал, то нужно смотреть на:
⭕️Дату последнего обновления библиотеки. Чем она ближе к текущей, тем лучше
⭕️Частоту обновления. Это может означать, что разработчик не забросил эту библиотеку и активно ее развивает
⭕️Количество скачиваний на pub.dev. Если их мало, то с такой библиотекой лучше не связываться
⭕️Issues на Github, если код открыт. Поможет понять, какие есть проблемы.
⭕️Прочитать ReadMe на предмет документации. Чтобы там не было всего пару строк, а было понятно, как использовать библиотеку
Если у вас большой опыт в Dart и Flutter, дополнительно можно посмотреть:
🟡Зависимости. Там не должно быть ничего лишнего
🟡Код библиотеки. Он должен быть понятен вам
🟡API Reference. Если библиотека плохо документирована, то лучше от нее отказаться
Рассказывайте в комментариях, а как вы выбираете библиотеки для своих проектов?
3 019
Hola, Amigos! Продолжаем рубрику с полезными extensions. Сегодня поговорим про расширение DateTime.
Можно получить информацию совпадает ли дата с сегодняшней, вчерашней или завтрашней:
extension DateTimeX on DateTime {
bool get isToday {
final now = DateTime.now();
return day == now.day && month == now.month && year == now.year;
}
bool get isTomorrow {
final now = DateTime.now();
return day == now.day + 1 && month == now.month && year == now.year;
}
bool get isYesterday {
final now = DateTime.now();
return day == now.day - 1 && month == now.month && year == now.year;
}
}
Можно получить сколько дней разницы до сегодня:
extension DateTimeX on DateTime {
int get daysDiff => this.difference(DateTime.now).inDays;
}
Делитесь в комментариях, про расширения для каких классов вы еще хотите узнать?
#extensions3 019
Hola, Amigos! Начинаем новую рубрику, где будем рассказывать вам про полезные Snippet’ы, которые вы можете добавить к себе в IDE для ускорения разработки. В дальнейшем ее найдете по хештегу #snippet. Сегодня поговорим про сниппеты для жизненного цикла
StatefulWidget.
Сниппет для быстрого добавления initState - initS:
@override
void initState() {
super.initState();
// Your code here
}
Сниппеты для быстрого добавления dispose - dis и disF:
@override
void dispose() {
// Your code here
super.dispose();
}
@override
Future<void> dispose() async {
// Your code here
super.dispose();
}
Пишите в комментариях, про какие сниппеты рассказать в следующий раз?3 019
Hola, Amigos! Наш Mobile Team Lead Павел Гершевич примет участие в активности под названием “Квартирник” на конференции CodeFest 16.
Квартирник - особый формат, где спикеры и эксперты общаются с залом на определенную тему. Павел вместе с Егором Поповым из Открытых Мобильных Платформ обсудят и ответят на вопросы касаемо кроссплатформы:
Почему одни фреймворки постоянно на слуху, а про другие мы не видим множества статей и докладов?
Есть ли границы у кроссплатформы? Можем ли мы написать одно приложение под все существующие устройства?
В чем преимущества и недостатки кроссплатформы?
Готовьте вопросы и приходите пообщаться с Павлом лично. Встречаемся 30 мая в 15:00 (11:00 МСК) на "Квартирнике" в Новосибирске!
Ссылка на квартирник
3 019
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga.
Иногда бэкенд не может помочь с поиском по строкам или его нужно реализовать полностью на локальных данных. Мы столкнулись именно с такой задачей.
В новой статье на Хабре разбираем, как прокачать локальный поиск с помощью математических алгоритмов и делимся нашим опытом реализации на Dart & Flutter.
🔗 Ссылка на статью
Делитесь в комментариях, сталкивались ли вы с похожими кейсами?
3 019
Дайджест марта-апреля
Hola Amigos! Собрали в одну подборку все полезные посты марта и апреля, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
🟡Кеширование картинок
🟡Пагинация на Flutter. Часть 1 и часть 2
🔴Статья про обновление токена при помощи Dio
🟡AppLifecycleState
🟡Создаем собственные snippets. В Android Studio и в VS Code
🟡Выбираем лицензию для библиотеки
🟡Полезные extensions для String
🟡Обфускация сборок
🟡Плагин Bloc для IDE
🟡RichText vs Text.rich
🟡Совершаем действия при тряске телефона
Всем хорошего кода!
3 019
+4
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. Сегодня мы разберем один интересный кейс - как сделать так, чтобы какое-то действие в приложении совершалось тогда, когда мы трясем телефон.
В этом нам конечно же помогут 2 популярные библиотеки -
sensors_plus и rxdart.
Пишите в комментариях, какое действие вы бы завязали на такой триггер?
P.S. А мы завязали один из триггеров открытия Amiga Dev Screen, который уже скоро вы сможете добавлять в свои проекты.3 019
Hola, Amigos! Сегодня мы посмотрим, чем отличаются 2 виджета для вывода текста -
RichText и Text.rich, а также разберемся, какой из них лучше использовать.
RichText из них основной. Он позволяет нам отрисовывать текст с применением нескольких стилей, а также добавлением виджетов внутрь. Простой пример применения - выделение части текста жирным или курсивом:
RichText(
text: TextSpan(
children: [
TextSpan(text: ‘Обычный текст. ‘, style: TextStyle(fontSize: 14, color: Colors.black)),
TextSpan(text: Жирный текст. ‘, style: TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold)),
TextSpan(text: ‘Снова обычный текст.‘, style: TextStyle(fontSize: 14, color: Colors.black)),
],
),
);
С другой стороны, нам нужно каждый раз применять стиль текста к RichText, а также передавать ему textScaler. Эту проблему можно решить при помощи Text.rich, но он уже менее гибкий, чем RichText, так как в нем сложнее сделать что-то по-максимуму кастомное.
Text.rich(
TextSpan(
children: [
TextSpan(text: ‘Обычный текст. ‘),
TextSpan(text: Жирный текст. ‘, style: TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold)),
TextSpan(text: ‘Снова обычный текст.‘),
],
),
);
Получается, что для большинства случаев нам подойдет именно Text.rich, а RichText нужен для максимальной кастомизации.
Рассказывайте в комментариях, какой из них чаще используете в своей работе?
Вже доступно! Дослідження Telegram за 2025 — головні інсайти року 
