Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead агентства продуктовой разработки Amiga. Сегодня мы снова поговорим про иконки приложения, но в этот раз про динамические, которые вы можете менять по воздуху или дать возможность пользователю выбрать самому. Про это мы нашли и перевели для вас подробную инструкцию.
Что вы сможете узнать из нее:
• Как добавить сразу несколько вариантов иконок в ваше приложение для iOS и Android;
• Как одновременно предоставить выбор пользователю для изменения настроек приложения и иногда самим их перезаписывать по воздуху;
🔗 Ссылка на переведенную статью
Делитесь в комментариях, пробовали ли вы менять иконку приложения таким способом?
Что вы сможете узнать из нее:
• Как добавить сразу несколько вариантов иконок в ваше приложение для iOS и Android;
• Как одновременно предоставить выбор пользователю для изменения настроек приложения и иногда самим их перезаписывать по воздуху;
🔗 Ссылка на переведенную статью
Делитесь в комментариях, пробовали ли вы менять иконку приложения таким способом?
🔥9🥰1
Hola Amigos! Собрали в одну подборку все полезные посты июня, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
🟡 Snippet для анимированного виджета
🟡 Форматируем код при сохранении
🟡 Кастомные иконки для iOS
🟡 Оптимизируем Assets. Часть 1. Часть 2. Часть 3.
🔴 Динамические иконки приложения на Flutter
Всем хорошего кода!
Всем хорошего кода!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9
Forwarded from Amiga
💸 Дешёвый старт, дорогой финал: как выбор технологии мстит команде спустя год
Планируете мобильное приложение и пока не определились со стеком? Прежде чем выбирать по цене и тому, с чем проще запускаться – стоит понимать, во что это выльется через год.
На старте всё выглядит логично: минимальный бюджет, быстрый MVP, разработчиков найти проще. Но экономия на технологии часто оборачивается совсем другими цифрами, когда продукт начинает расти.
В статье разбираем, как решения, которые кажутся выгодными на первом этапе, влияют на скорость обновлений, производительность, стоимость команды через год-два – и как понять цену выбора до того, как проект будет написан.
🔗 https://amiga.ru/blog/flutter-vs-react-native-vs-kmp-vybor-steka-2026
Планируете мобильное приложение и пока не определились со стеком? Прежде чем выбирать по цене и тому, с чем проще запускаться – стоит понимать, во что это выльется через год.
На старте всё выглядит логично: минимальный бюджет, быстрый MVP, разработчиков найти проще. Но экономия на технологии часто оборачивается совсем другими цифрами, когда продукт начинает расти.
В статье разбираем, как решения, которые кажутся выгодными на первом этапе, влияют на скорость обновлений, производительность, стоимость команды через год-два – и как понять цену выбора до того, как проект будет написан.
🔗 https://amiga.ru/blog/flutter-vs-react-native-vs-kmp-vybor-steka-2026
🔥4👍2
Hola, Amigos! Продолжаем разговаривать про настройку наших IDE. В этот раз разберемся, как мы можем работать с импортами в наших
Для Android Studio перейдем в настройки IDE (Settings на Windows и Linux, Preferences на macOS), там в “Languages & Frameworks” и выберем Flutter. У нас откроется окно настроек плагина, где у нас уже включен чекбокс “Format code on save”. Под ним есть еще один - “Organize imports on save”, именно он нам и нужен - включаем его.
Для VS Code все немного проще. В
Теперь при сохранении файла, наши импорты будут упорядочены, но желательно еще настроить правила линтера для этого в нашем
или
Таким образом, наши импорты будут выстраиваться так:
• Импорты из Dart
• Импорты из библиотек, самого фреймворка или статические импорты из проекта
• Локальные импорты по проекту, без использования package:
Например:
Делитесь в комментариях, включена ли у вас эта настройка и как вы организуете импорты на ваших проектах?
.dart файлах и как их настроить, чтобы они сортировались и удалялись, если не используются, автоматически.Для Android Studio перейдем в настройки IDE (Settings на Windows и Linux, Preferences на macOS), там в “Languages & Frameworks” и выберем Flutter. У нас откроется окно настроек плагина, где у нас уже включен чекбокс “Format code on save”. Под ним есть еще один - “Organize imports on save”, именно он нам и нужен - включаем его.
Для VS Code все немного проще. В
settings.json нужно всего лишь включить:
“editor.codeActionsOnSave”: {
“source.organizeImports”: true
}
Теперь при сохранении файла, наши импорты будут упорядочены, но желательно еще настроить правила линтера для этого в нашем
analysis_options.yaml:
linter:
rules:
- directives_ordering
или
linter:
rules:
directives_ordering: true
Таким образом, наши импорты будут выстраиваться так:
• Импорты из Dart
• Импорты из библиотек, самого фреймворка или статические импорты из проекта
• Локальные импорты по проекту, без использования package:
Например:
import ‘dart:async’;
import ‘package:flutter/material.dart’;
import ‘package:flutter_bloc/flutter_bloc.dart’;
import ‘package:my_app/common/widgets.dart’;
import ‘widgets/app_bar.dart’;
import ‘../../navigation.dart’;
Делитесь в комментариях, включена ли у вас эта настройка и как вы организуете импорты на ваших проектах?
🔥8👍4
Hola, Amigos! Сегодня мы хотим рассказать про один из редко используемых, но очень полезных виджетов -
Представьте, что вы делаете сложную верстку, где несколько кнопок с текстом должны быть расставлены горизонтально и занимать максимально доступную ширину. Если текста больше, чем нужно, а это может быть при увеличенном шрифте, то одну кнопку мы переносим на следующую строку.
Сначала кажется верным использовать
И вместо
Мы можем сделать так:
Как мы видим, этот виджет больше похож на
Делитесь в комментариях, использовали ли данный виджет на своих проектах?
OverflowBar.Представьте, что вы делаете сложную верстку, где несколько кнопок с текстом должны быть расставлены горизонтально и занимать максимально доступную ширину. Если текста больше, чем нужно, а это может быть при увеличенном шрифте, то одну кнопку мы переносим на следующую строку.
Сначала кажется верным использовать
Row или Wrap. Но тут мы встречаемся с проблемой - при использовании первого, мы не можем перенести дочерние виджеты, а со вторым не можем растянуть их. Третий вариант - использовать LayoutBuilder и вычислять размеры самим, но это сложно. Вот тут то нам и приходит на помощь виджет OverflowBar.И вместо
Row(
mainAxisAlignment: MainAxisAlignment.end,
spacing: 8,
children: [
TextButton(onPressed: () {}, child: Text("Cancel")),
TextButton(onPressed: () {}, child: Text("Save")),
ElevatedButton(onPressed: () {}, child: Text("Delete")),
],
)
Мы можем сделать так:
OverflowBar(
alignment: MainAxisAlignment.end,
spacing: 8,
overflowSpacing: 8,
children: [
TextButton(onPressed: () {}, child: Text("Cancel")),
TextButton(onPressed: () {}, child: Text("Save")),
ElevatedButton(onPressed: () {}, child: Text("Delete")),
],
)
Как мы видим, этот виджет больше похож на
Wrap, но он работает как смесь Wrap и Row.Делитесь в комментариях, использовали ли данный виджет на своих проектах?
👍19🔥6❤3
Hola, Amigos! Продолжаем рассказывать про полезные виджеты. Сегодня на очереди
Во время разработки экрана со сложной версткой и использовании на нем
Ранее для этого писали собственные решения или использовали виджет
Сейчас для выноса нескольких сливеров в отдельный виджет есть
Делитесь в комментариях, используете ли данный виджет на своих проектах или все еще делаете по старинке?
SliverMainAxisGroup, который позволит нам увеличить читаемость кода.Во время разработки экрана со сложной версткой и использовании на нем
CustomScrollView, может случиться ситуация, когда количество используемых сливеров становится слишком большим. Из-за этого кода становится настолько много, что его читаемость сильно падает. И тут встает вопрос о выносе некоторых сливеров в отдельный виджет.Ранее для этого писали собственные решения или использовали виджет
MultiSliver из библиотеки sliver_tools. Но время идет, фреймворк обновляется, а старые решения работают все хуже. Например, sliver_tools уже пару лет не обновляется и ее использование может отражаться на производительности приложений.Сейчас для выноса нескольких сливеров в отдельный виджет есть
SliverMainAxisGroup, который работает из коробки. Давайте на него посмотрим:
SliverMainAxisGroup(
slivers: [...]
);
Делитесь в комментариях, используете ли данный виджет на своих проектах или все еще делаете по старинке?
🔥9❤4
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. В этой небольшой серии мы разберем, как кастомизировать виджеты
Делается это как и внутри самого виджета, так и через тему. Начнём с простого кейса: внешний вид слайдера нас устраивает, но нужно изменить только цветовую схему.
Эти три параметра позволяют быстро адаптировать внешний вид Slider:
•
•
•
Те же настройки доступны и для RangeSlider.
Если нужно применять стили сразу ко всем слайдерам в приложении, удобнее вынести их в тему:
Как мы видим, свойство
В следующей части поговорим о более глубокой кастомизации — разберём, как создать собственный индикатор выбранного значения для
А пока делитесь в комментариях: приходилось ли вам менять стандартный вид этих виджетов? Какие настройки использовали?
Slider и RangeSlider, чтобы они лучше соответствовали вашему дизайну.Делается это как и внутри самого виджета, так и через тему. Начнём с простого кейса: внешний вид слайдера нас устраивает, но нужно изменить только цветовую схему.
Slider(
… // Основные настройки слайдера
activeColor: Colors.red,
inactiveColor: Colors.blue,
overlayColor: WidgetStatePropertyAll(Colors.green),
);
Эти три параметра позволяют быстро адаптировать внешний вид Slider:
•
activeColor отвечает за цвет активной части полосы — от начального значения до текущей позиции, а также за цвет индикатора выбранного значения;•
inactiveColor задаёт цвет неактивной части полосы;•
overlayColor позволяет перекрасить цвет выделения, которое показывается при перемещении индикатора.Те же настройки доступны и для RangeSlider.
Если нужно применять стили сразу ко всем слайдерам в приложении, удобнее вынести их в тему:
SliderThemeData(
activeTrackColor: Colors.red,
thumbColor: Colors.red,
inactiveTrackColor: Colors.blue,
overlayColor: Colors.green,
)
Как мы видим, свойство
activeColor - разделилось на два: activeTrackColor отвечает за полосу, а thumbColor за индикатор выбранного значения. Кроме этого, тема позволяет кастомизировать и цвета для отключенных виджетов при помощи таких же свойств, только с префиксом disabled.В следующей части поговорим о более глубокой кастомизации — разберём, как создать собственный индикатор выбранного значения для
Slider и RangeSlider.А пока делитесь в комментариях: приходилось ли вам менять стандартный вид этих виджетов? Какие настройки использовали?
🔥4❤1
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. В прошлой части мы рассмотрели базовую кастомизацию виджетов
Для этого нам нужно будет создать отдельный класс, который наследуется от
Сначала, нам нужно задать размер нашего индикатора. В нашем примере он круглый, поэтому идем от радиуса большего круга.
Далее наступает момент отрисовать на канвасе. Делается это точно также как и при использовании
Для
•
•
•
•
Остальные параметры могут быть не настолько полезны, кроме тех, что используются при отрисовке текста. Например, выбранного значения.
Для
•
•
Давайте нарисуем наш индикатор для обычного
Теперь нужно добавить наш готовый индикатор в тему:
В следующей части мы рассмотрим, как кастомизировать полосу со значениями.
Пишите в комментариях, если уже пробовали кастомизировать слайдеры своими руками! 👇
Slider и RangeSlider. Сегодня мы углубимся в детали и изменим внешний вид индикатора у слайдера.Для этого нам нужно будет создать отдельный класс, который наследуется от
SliderComponentShape для Slider или RangeSliderThumbShape для RangeSlider:
class AppThumbShape extends SliderComponentShape
class AppRangeThumbShape extends RangeSliderThumbShape
Сначала, нам нужно задать размер нашего индикатора. В нашем примере он круглый, поэтому идем от радиуса большего круга.
@override
Size getPrefferedSize(bool isEnabled, bool isDiscrete) => Size.fromRadius(8);
Далее наступает момент отрисовать на канвасе. Делается это точно также как и при использовании
CustomPaint, только свойства у методов немного другие. Давайте на них посмотрим.Для
SliderComponentShape это:•
PaintingContext, который нам и выдает канвас для отрисовки;•
Offset center - координаты центра канваса;•
activationAnimation и enableAnimation - анимации начала взаимодействия и включения / выключения слайдера;•
sliderTheme - тема для получения цветов и всего необходимого, что мы уже настроили ранее;Остальные параметры могут быть не настолько полезны, кроме тех, что используются при отрисовке текста. Например, выбранного значения.
Для
RangeSliderThumbShape добавляются:•
bool isOnTop - показывает, находится ли этот индикатор над другим;•
Thumb thumb - какой это именно индикатор - в начале или в конце интервала.Давайте нарисуем наш индикатор для обычного
Slider:
@override
void paint(
PaintingContext context,
Offset center, {
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
) {
final canvas = context.canvas;
final redPaint = Paint()
..color = Colors.red
..style = PaintingStyle.fill;
final whitePaint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
canvas
..drawCircle(center, 8, redPaint)
..drawCircle(center, 6, whitePaint)
..drawCircle(center, 3, redPaint);
}
Теперь нужно добавить наш готовый индикатор в тему:
SliderThemeData(
…,
thumbShape: AppThumbShape(),
rangeThumbShape: AppRangeThumbShape(),
)
В следующей части мы рассмотрим, как кастомизировать полосу со значениями.
Пишите в комментариях, если уже пробовали кастомизировать слайдеры своими руками! 👇
❤3
Hola, Amigos! На связи Павел Гершевич, Mobile Team Lead в Amiga. В прошлых частях мы разобрали базовую кастомизацию виджетов
Для этого нам так же, как и с индикатором, нужно создать отдельный класс, наследуемый от
Данные классы отличаются от тех, которые мы применяли в прошлой части, так как вместо метода на получение размера, тут есть метод на получение объекта
После чего переопределяем метод для отрисовки. В нашем примере полоса всегда будет одинаковой, поэтому мы рисуем только один
Если вы хотите показывать часть полосы до индикатора одним стилем, а после - другим, то на помощь придет свойство
Для
Для того, чтобы применить наш стиль нужно добавить классы к теме:
Небольшая рекомендация от нас - если применяете собственную отрисовку трека, то лучше всего
Рассказывайте в комментариях, кастомизацию каких виджетов хотели бы увидеть?🙂
Slider и RangeSlider, а также замену индикатора на собственный. Сегодня мы займемся изменением полосы значений (Track) под наш дизайн.Для этого нам так же, как и с индикатором, нужно создать отдельный класс, наследуемый от
SliderTrackShape для Slider и RangeSliderTrackShape для RangeSlider.Данные классы отличаются от тех, которые мы применяли в прошлой части, так как вместо метода на получение размера, тут есть метод на получение объекта
Rect. Для примера выберем самое простое - задать только размеры:
@override
Rect getPreferredRect({
required RenderBox parentBox,
Offset offset = Offset.zero,
required SliderThemeData sliderTheme,
bool isEnabled,
bool isDiscrete
}) {
return Rect.fromTLWH(0, 0, parentBox.constraints.width, 8.0);
}
После чего переопределяем метод для отрисовки. В нашем примере полоса всегда будет одинаковой, поэтому мы рисуем только один
RRect:
@override
void void paint(
PaintingContext context,
Offset offset, {
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required Animation<double> enableAnimation,
required Offset thumbCenter,
Offset? secondaryOffset,
bool? isEnabled,
bool? isDiscrete,
required TextDirection textDirection
}) {
final trackRect = Rect.fromTLWH(0, 0, parentBox.constraints.width, 8.0);
final trackRRect = RRect.fromRectAndRadius(trackRect, Radius.circular(4);
final redPaint = Paint()
..color = Colors.red
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
final whitePaint = Paint()
..color = Colors.white
..style = PaintingStyle.fill;
canvas
..drawRRect(trackRRect, whitePaint)
..drawRRect(trackRRect, redPaint);
}
Если вы хотите показывать часть полосы до индикатора одним стилем, а после - другим, то на помощь придет свойство
thumbCenter. Оно означает координаты центра индикатора:
final trackRectBefore = Rect.fromPoints(
Offset.zero,
Offset(thumbCenter.dx, 8.0),
);
final trackRectAfter = Rect.fromPoints(
Offset(thumbCenter.dx, 0),
Offset(parentBox.constraints.width, 8.0),
);
Для
RangeSliderTrackShape будут доступны два таких свойства - startThumbCenter и endThumbCenter. С их помощью можно разделить трек на три зоны: неактивную область до начального индикатора, активную область между индикаторами и неактивную область после конечного индикатора.Для того, чтобы применить наш стиль нужно добавить классы к теме:
SliderThemeData(
…,
trackShape: AppSliderTrackShape(),
rangeTrackShape: AppRangeSliderTrackShape(),
)
Небольшая рекомендация от нас - если применяете собственную отрисовку трека, то лучше всего
Slider будет оборачивать в SizedBox для лучшего позиционирования на экране.Рассказывайте в комментариях, кастомизацию каких виджетов хотели бы увидеть?
Please open Telegram to view this post
VIEW IN TELEGRAM
1👌2🔥1
Hola, Amigos! Сегодня мы вводим новую рубрику - обзоры правил для статического анализатора #lintRules.
В ней мы будем рассказывать о тех правилах, которыми пользуемся сами на наших проектах.
Поэтому ловите первую подборку. А также рассказывайте в комментариях, про какие правила рассказать в следующий раз?
В ней мы будем рассказывать о тех правилах, которыми пользуемся сами на наших проектах.
Поэтому ловите первую подборку. А также рассказывайте в комментариях, про какие правила рассказать в следующий раз?
👍17
Hola, Amigos! Сегодня посмотрим на один пакет, который может быть полезен в разработке - paged_vertical_calendar.
Он выводит календарь непрерывным вертикальным списком вместо одного месяца переключением. Это полезно в таких случаях:
⭕️ Нужно показать сразу несколько месяцев;
⭕️ Есть выбор интервала дат, которые могут быть в разных месяцах;
⭕️ Нужен другой UX, чем стандартный.
Давайте разберем его базовое использование:
Пройдемся по его параметрам:
•
•
•
•
•
•
Так как это все-таки список, то ему доступны еще параметры, которые есть у других похожих виджетов -
Но самое интересное и важное, что такой календарь можно максимально кастомизировать под себя следующими параметрами:
•
•
•
•
•
Рассказывайте, решали ли уже подобные задачи и пользовались ли этим пакетом в своих проектах?
Он выводит календарь непрерывным вертикальным списком вместо одного месяца переключением. Это полезно в таких случаях:
Давайте разберем его базовое использование:
PagedVerticalCalendar(
minDate: DateTime.now().subtract(Duration(days 365)),
maxDate: DateTime.now().add(Duration(days 365)),
initialDate: DateTime.now().add(Duration(days 3)),
invisibleMonthsThreshold: 1,
startWeekWithSunday: true,
onMonthLoaded: (year, month) {
// on month widget load
},
onDayPressed: (value) {
// on day widget pressed
},
onPaginationCompleted: (direction) {
// on pagination completion
},
);
Пройдемся по его параметрам:
•
minDate и maxDate помогают нам сделать календарь не бесконечным;•
initialDate - дата начального месяца, который будет показан пользователю посередине списка;•
invisibleMonthThreshold - количество месяцев, которые пользователь не видит, но они просчитываются для дальнейшего отображения;•
startWeekWithSunday - полезное свойство, если приложение работает в странах, где неделя начинается с воскресенья, а не с понедельника;•
onMonthLoaded, onPaginationCompleted - обратные вызовы, которые помогают подгружать данные, если это нужно;•
onDayPressed - обработка нажатия на какой-либо день.Так как это все-таки список, то ему доступны еще параметры, которые есть у других похожих виджетов -
controller, physics, addAutomaticKeepAlives и reverse.Но самое интересное и важное, что такой календарь можно максимально кастомизировать под себя следующими параметрами:
•
dayAspectRatio - помогает задать соотношение сторон для виджета дня;•
weekdaysToHide - скрывает дни недели, если нужно показать только определенные. Например, только рабочие дни;•
listPadding - позволяет задать отступы у списка;•
monthBuilder - позволяет кастомизировать шапку месяца под себя;•
dayBuilder - позволяет кастомизировать отображение дня на календаре.Рассказывайте, решали ли уже подобные задачи и пользовались ли этим пакетом в своих проектах?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1🔥1
Дайджест июля
Hola, Amigos! Собрали в одну подборку все полезные посты июля, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
🔴 Организация импортов в проекте;
🔴 Обзоры виджетов OverflowBar и SliverMainAxisGroup;
🔴 Кастомизация виджета Slider - Часть 1. Часть 2. Часть 3;
🔴 Правила статического анализа;
🔴 Обзор пакета paged_vertical_calendar.
Всем хорошего кода!
Hola, Amigos! Собрали в одну подборку все полезные посты июля, которые вы могли пропустить. Выбирайте, что интересно, и переходите по ссылкам для полезного выходного чтива:
Всем хорошего кода!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3