Surf Flutter Team – Telegram
Surf Flutter Team
3.13K subscribers
676 photos
54 videos
265 links
Комьюнити Flutter-разработчиков Surf.

🛠 Разработали решения для KFC, Росбанка и Medium Quality
📚 Делимся полезными материалами и обучаем стажёров

💬 Чат → https://news.1rj.ru/str/+aJbtJ4znXCBhOGIy

🧑🏻‍💻 Вакансии: career.surf.ru
📲 По вопросам @SurfAskBot
Download Telegram
Обёртки над необычными модулями? Это не так сложно, как кажется. Часть 1

Привет! Меня зовут Алексей Земцов, я Flutter-разработчик.

Расскажу про недавний опыт подключения к проекту довольно специфичного модуля сканера штрихкодов.

Сканеры в проекте представлены в двух вариантах:
1️⃣ Встроенный сканер в Android-смартфоны Urovo.
2️⃣ В формате чехла для iPhone и iPod — Linea Pro.

Несмотря на кажущуюся необычность задачи, в итоге всё свелось к:
🔹 Подключению к проекту нативных библиотек от производителей устройств.
🔹 Имплементации нужных методов через через platform-channel.
🔹 Объединению их в общий сервис под единый интерфейс.

В следующих постах расскажу обо всём подробнее.
🔥20👍3
Обёртки над необычными модулями: часть 2. Подключение к проекту нативных библиотек от производителей устройств

Подключить нативную библиотеку к проекту можно как минимум двумя способами:
1. «В лоб»: работая с папками /ios/ и /android/ в корне проекта.
2. Создать Flutter-плагин и подключить его к проекту через pubspec.yaml. Это удобно: модуль гораздо проще шарить между проектами и даже можно выложить на pub.dev.
Если это ваш первый опыт, лучше идти от первого пункта ко второму, экспериментируя на пустом проекте.

Подключение библиотеки к пустому Flutter-проекту

Библиотеки подключаются по инструкциям от производителя. Их можно найти на официальных сайтах и в readme примеров на github.

👉 В случае со сканером штрих-кодов подключить .jar-библиотеку к Android оказалось несложно: открываешь папку android в корне проекта и действуешь по инструкции.

👉 Для iOS небольшое расхождение с инструкцией возникло: на вкладке проекта Build Settings в строчке Objective-C Bridging Header нужно было указать ссылку на заголовочный файл библиотеки DTDevices.h, но в нормальном Flutter-приложении там уже указана ссылка на Runner-Bridging-Header.h.

Решение оказалось простым: открыть этот Runner-Bridging-Header.h файл и импортировать заголовочный файл в него 🙂

Вынесение библиотеки в нативный плагин

После экспериментов с пустыми проектами и привязкой к нему методов библиотек через method-channel пришло время выносить изменения в отдельный плагин.

Как создать плагин, описывать не буду. На официальном сайте есть отличная статья на эту тему.

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

Осложняло отладку кода то, что анализатор Android Studio не хотел воспринимать плагин как целый проект и при открытии Kotlin/Java-файла с расписанными method-channel отказывался подсвечивать ошибки.

Решение оказалось тривиальным: нужно открывать папку android не в плагине `/название_плагина/android/`, а в примере его использования `/название_плагина/example/android/`. В таком случае Android Studio отображает две папки Android, в одной из которых лежат файлы нашего пакета.
🔥17👍1
Обёртки над необычными модулями: часть 3. Подключение к основному проекту

После имплементации и отладки нужных функций оба пакета поселились в директории основного проекта. Подключены они через pubspec.yaml.

На стороне проекта был написан сервис, объединяющий их в единый интерфейс.
__

Каким бы экзотическим не казалось устройство, подключаемое к проекту, скорее всего производитель написал библиотеку/SDK и инструкцию для нативных платформ. Совсем несложно обернуть её в простенький Flutter-плагин, а понимание базовых концепции работы нативных платформ поможет справится с проблемами, которые не описаны в мануалах.
👍17🔥2
Как оценивать задачи. Часть 1

Предположим, пришёл заказчик и попросил реализовать экран👆

Как оценить задачу: сроки, трудозатраты?

Меня зовут Дима Шевченко, я Tech Lead Flutter Surf. Расскажу, как правильно подходить к оценке, чтобы не краснеть за сорванные дедлайны.

Составим вопросы для понимания задачи. Иногда ответы на них есть в ТЗ, но иногда информации недостаточно:

• Бэкенд готов? Если нет, когда можно ожидать готовность?
• Реализована ли нижняя навигация? Если нет, включаем в оценку?
• Что должно происходить во время нажатия на кнопку фильтрации в поиске: всплывающее окно или отдельный экран?
• Что должно происходить при нажатии на карточку?

Ответы на эти вопросы помогут точнее декомпозировать задачу и сделать оценку. В нашем случае необходимо реализовать самую простую функциональность: отображение списка мест и поиск.
🔥182
Как оценивать задачи. Часть 2: из чего состоит задача

Первый шаг:

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

Примерное представление о содержании полей необходимо для понимания сложности конкретного класса.

На нашем экране можно выделить две сущности:

— Сущность, которая описывает место: название места, тип места, id места, рабочее время.
— Рабочее время.
🔥8🐳1
Второй шаг: выделить классы Repository, которые будут отвечать за получение данных и первоначальную работу с ними, — PlaceRepository.

В нашем случае нужно получать список мест из сети. Есть возможность добавить место в избранное.

Чтобы использовать локальное хранилище и работать со списком офлайн, необходимо реализовать два DataSource-класса:

• RemotePlaceDataSource
• LocalPlaceDataSource

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

Опционально можно подумать о том, что должно располагаться в доменном слое. Но он необязателен и нужен не всем приложениям.
🔥5
Третий шаг: выделить UI-компоненты и то, как работать с внешними виджетами приложения.

Перед нами экран, в рамках которого необходимо реализовать:

• заголовок страницы с текстовым полем поиска,
• список с карточками мест,
• карточку места,
• функциональную кнопку «лайк».

На самой странице отчетливо выделяются состояния (стейты):

• состояние списка мест,
• состояние нажатие кнопки,
• к состоянию также можно отнести значения ввода в текстовое поле.

Бизнес логика UI:

• получения данных;
• обновление данных (pull to refresh);
• поиск локальный и удаленный,
• добавление и удаление из избранного.

🌟 Теперь перед нами полная картина. Чтобы дать окончательную оценку, осталось понять, сколько времени уйдет на реализацию каждого компонента. Для этого я пользуюсь таблицей на основе личного опыта и опыта коллег 👇👇👇
👍1
Как оценивать задачи. Часть 3: таблица временных затрат

Обратить на колонки с заголовками Story point.

Первая колонка (1 Story point) рассчитывается по формуле, которая описана в методике PERT: (a + 4m + b) / 6

a – минимальное время, m – предполагаемое время, b – максимальное время

Во второй и третьей колонке значения умножаются на 1,5 и 3 соответственно.

Поскольку компоненты могут иметь различный уровень сложности, к отдельному взятому компоненту можно указать дополнительный коэффициент от 1 до 3 в зависимости от сложности. Таким образом, значение веса по времени будет выбираться из соответствующей колонки Story point.

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

Расскажите, а как вы подходите к оценке задач?
🔥6
Пять плагинов для продуктивного написания кода

Всем привет 👋

Меня зовут Иван Таранов, я Flutter-разработчик в Surf. Сегодня расскажу, как улучшить пользовательский опыт работы в IDE и повысить продуктивность при написании кода с помощью плагинов.

В посте разберём плагины для Android Studio: это та среда, которой я пользуюсь. Но аналоги этих инструментов присутствуют и в VS Code.

Поговорим о:
🔹Шорткатах с помощью KeyPromoter X
🔹Изменении строк с помощью String Manipulator
🔹Кастомизации иконок с помощью Atom Material Icons
🔹Упрощении работы с зависимостями с помощью Flutter Enhancement Suite
🔹Спецэффектах с помощью Power Mode II
🔥16🍌1
This media is not supported in your browser
VIEW IN TELEGRAM
1️⃣ KeyPromoter X: больше шорткатов богу шорткатов

Скажу честно, мне очень нравятся комбинации клавиш. С их помощью я могу очень быстро совершать рутинные задачи: навигацию в IDE, манипуляцию с файлами, дебаггинг приложения и многое другое. Если какую-то комбинацию пропустил, плагин подскажет о её существовании. Очень просто, а главное — полезно 👍
👍102🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
2️⃣ String Manipulation: изменение строк

Зачастую приходится рефакторить строковые данные, и нет ничего хуже, чем необходимость вручную перебирать форматы: camel case в snake case или наоборот.

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

Здесь на помощь приходит String Manipulation — плагин, позволяющий совершать десятки превращений строковых данных. Это, несомненно, сохраняет время и рассудок.
👍10🔥5
3️⃣ Atom Material Icons: иконки — просто космос

Мне не нравится, как выглядит стандартная IDE. Возможно, это личная проблема, но я воспринимаю среду разработки с дефолтной темой как стандартные обои на телефоне или пустой рабочий стол.

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

В общем, повышение читаемости и лёгкость навигации в коде — однозначно плюс.
👍8🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
4️⃣ Flutter Enhancement Suite — упрощение работы с зависимостями для Flutter

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

Также он выдаёт контекстные подсказки, какие плагины существуют с похожим названием: это значительно упрощает добавление новых зависимостей в проект.
👍10🔥3🍌1
This media is not supported in your browser
VIEW IN TELEGRAM
5️⃣ Power Mode II: когда надо показать коду, кто тут главный

Самое лучшее я оставил напоследок 😂

Power Typer — плагин, создающий взрывы и спецэффекты при наборе, вставке или изменении кода в редакторе.

Бывает полезно для лайв-кодинга или парного программирования: с 🔥 и 💥 на экране тяжело отвлечься даже от скучного рефакторинга. А ещё эффекты помогают следить за местоположением курсора.

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

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

А какими плагинами пользуетесь вы? Делитесь обязательно в комментариях 👇
👍16🔥5🏆21🙏1
ООП в Dart: особенности реализации

Давайте поговорим про Dart — язык, на котором пишут все Flutter-разработчики.

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

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

Итак, Dart — объектно-ориентированный язык программирования (ООП) с сильной статической типизацией и поддержкой обобщённого программирования.

Что всё это значит

ООП — методология программирования, основанная на представлении программы в виде совокупности объектов: каждый является экземпляром определённого класса, а классы образуют иерархию наследования.

Сильная типизация. Язык не позволяет смешивать в выражениях различные типы и не выполняет автоматические неявные преобразования: например, нельзя прибавить к строке число.

Статическая типизация. Конечные типы переменных и функций устанавливаются на этапе компиляции: компилятор на 100% уверен, где какой тип находится.

Четыре основных принципа ООП

• инкапсуляция,
• наследование,
• абстракция,
• полиморфизм.

Объектно-ориентированное программирование в рамках Dart хоть и похоже на ООП в C++, C#, Java или Kotlin, но имеет некоторые особенности, о которых мы расскажем в следующих постах.
👍25💩31
Чистая архитектура с Elementary

Для разработки Flutter-проектов мы используем внутреннее решение — библиотеку Elementary. Она опирается на архитектурный паттерн Model-View-ViewModel (MVVM).

Elementary помогает писать приложение по правилам Clean Architecture с разделением модулей на чёткие блоки согласно ответственностям:
🔹 UIхранится в ElementaryWidget,
🔹 бизнес-логикав ElementaryModel,
🔹 презентационная логикав WidgetModel (WM).

Благодаря такому разделению код становится проще для восприятия и тестирования.

👉 Подробнее об Elementary читайте в статье «Elementary: новый взгляд на архитектуру Flutter-приложений»
👉 Сам пакет Elementary доступен на pub.dev

🙋Уже знакомы с Elementary? Как впечатления?
🔥18
Особенности инкапсуляции в Dart

Привет! С вами Дима Шевченко, Flutter-разработчик Surf, и мы продолжаем серию постов про ООП.

Первый пост: что такое ООП

Сегодня поговорим про инкапсуляцию.

Инкапсуляция – свойство системы, позволяющее:

🔹объединить данные и методы, работающие с ними, в классе.
🔹скрыть детали реализации от пользователя,
🔹открыть только то, что необходимо при последующем использовании.

Коммуникации в подвале дома, внутренности смартфона или автомобиля — так выглядит инкапсуляция в реальной жизни 😁

Чтобы скрыть данные, во многих ООП-языках существуют модификаторы доступа:

publiс — к свойству и методу может получить доступ любой желающий;
private — к свойству и методу могут обращаться только методы данного класса;
protected — то же, что и private, только доступ получают и наследники класса в том числе.

В языке Dart отдельных модификаторов доступа нет🙅

Приватность свойств и методов можно задать только на уровне файла. Приватными считаются все члены класса, чьё имя начинается с подчеркивания "_".

class Person {
final String _name;
final DateTime _birthday;

Person(this._name, this._birthday);

int getAge() => DateTime.now().difference(_birthday).inDays ~/ 365;
}


Для обозначения protected можно использовать аннотацию @рrotected из пакета meta: она предупреждает о неверном поведении, если использовать свойство вне наследника или родителя.

______
В следующих постах продолжим разговор про ООП: разберём особенности наследования, абстракции и полиморфизма в Dart 🙌
🔥22👍2👎2
This media is not supported in your browser
VIEW IN TELEGRAM
Анимации во Flutter — так ли это сложно

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

Новички часто воспринимают анимации как продвинутую тему, но на самом деле в этом нет ничего сложного.

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

Чтобы сделать минимальную красивую анимацию во Flutter, нужно знать только, что такое:

🔹 Duration, длительность анимации — время, которое анимация будет проигрываться.
🔹 Curve, кривая — функция, которая задаёт, как анимация будет двигаться в это время.

С этими знаниями уже можно создавать красивые анимации.

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

Чаще всего на практике мне приходится использовать виджеты AnimatedAlign, AnimatedOpacity и AnimatedContainer.
🔥20👍3