Хабрахабр

Flutter — новый взгляд на кроссплатформенную разработку

В августе 2018 года Flutter стал самой запрашиваемой кроссплатформенной технологией на Stack Overflow.

image

В нашем блоге Артем Зайцев и Евгений Сатуров из студии Surf, сертифицированного агентства Google, расскажут, почему и как так получилось:

Причина проста — единая кодовая база. Кроссплатформенные решения давно привлекают желающих быстро и незатратно запустить MVP-продукт одновременно под несколько платформ. Да и людей для ее поддержки и создания требуется меньше — нет необходимости содержать двух нативных разработчиков. Ее легче поддерживать: артефакты централизованы, нет дублирования логики и правок одних и тех же багов под каждую из платформ.

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

Подчеркну, что он предназначен именно для мобильных приложений и охватывает две платформы: Android и iOS. Совсем скоро ожидается финальный релиз нового фреймворка для мобильной разработки от Google — Flutter, который стал самой запрашиваемой кроссплатформенной технологией на Stack Overflow. Новые проекты на Flutter попадают в специальную подборку, цель которой — показать возможности фреймворка. На данный момент представлена Release Preview 2 версия. Сейчас фреймворк активно пополняется компонентами и архитектурными надстройками благодаря сообществу разработчиков (например, реализация Redux).

Почему нужно поверить во Flutter?

Отличный тулинг для быстрой разработки

При помощи плагина она отлично приспосабливается под разработку Flutter-приложений. Вам не придётся вылезать из привычной Android Studio.

Hot Reload — киллер-фича, позволяющая моментально переносить все изменения из кода на запущенный эмулятор или подключенное устройство.

Простота и выразительность вёрстки

Если вы когда-либо разрабатывали приложения под Android, уверен, вёрстка — это не то, от чего вы получали удовольствие.

Во-первых, никаких XML-файлов с вёрсткой — виджеты создаются и настраиваются прямо в коде (чем-то напоминает Anko Layouts). С Flutter всё иначе. Вместо View используются Widget.

new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: EdgeInsets.all(16.0), child: Text( '$_name', ), ), //...

Поначалу огромное количество скобок пугает, но такие “деревья” довольно наглядны. Так выглядит код Flutter-проекта. Почти у любого компонента есть свойство child или children, которое принимает другой элемент или массив элементов соответственно. Flutter пропагандирует композицию: из готовых виджетов можно составить новый, как из конструктора. Сделать красивый пользовательский интерфейс можно достаточно быстро. Все просто и понятно.

Он содержит два набора элементов, Material Components и Cupertino, которые выглядят нативно для каждой из платформ. Во-вторых, прямо со старта создатели платформы предлагают разработчикам каталог готовых виджетов. Их внешний вид и поведение идентичны на iOS и на Android-устройствах. Кроме того, доступны кроссплатформенные виджеты.

Реактивный фреймворк

Dart отдалённо напоминает Java, JavaScript, C#. Создать красивый и приятный UI в сжатые сроки можно не только благодаря большому количеству готовых виджетов, но и языку, на котором вам придётся писать. Он выразителен и отлично заточен под нужды фреймворка, хотя, после Kotlin некоторые художественные излишества синтаксиса могут ввести в легкий ступор.

“Под капотом” он использует Skia в качестве графического движка. Flutter компилируется в нативный код под каждую из платформ.

Именно отсутствие необходимости в переключении контекста и использования "мостов" даёт прирост производительности, который, способствует достижению заветного показателя в 60 FPS при отрисовке UI. Ключевой особенностью архитектуры системы является то, что все виджеты, а также компоненты, ответственные за отрисовку виджетов на канве, являются частью приложения, а не платформы.

Вся мощь платформы по-прежнему в ваших руках

Все библиотеки, доступные в нативных приложениях SDK и платформенные API могут быть использованы для Flutter-приложений. Зачем отказываться от тонны полезного кода, который целое десятилетие создается в сообществе мобильных разработчиков?

Настройка окружения

Начать работу с Flutter очень просто.

При разработке официальная документация советует использовать Android Studio, IntelliJ или VSCode c соответствующими плагинами, но подойдет любой текстовый редактор.

Шаг первый

Распаковать в желаемую директорию и запустить команду flutter doctor. Скачать архив с Flutter SDK с официального сайта под свою ОС. Данная команда проверит установлено ли все необходимое, а также — наличие плагинов под установленные IDE (например, при установленной Android Studio утилита проверит плагины под нее).

Шаг второй

Если найдены ошибки, doctor подскажет как их решить. Если все прошло гладко, можно приступать к созданию первого проекта.

Шаг третий

Установить их можно стандартным образом, открыв настройки и выбрав нужные плагины в поиске. Для использования Flutter в Android Studio необходимо поставить два плагина: Flutter и Dart.

Подробно о настройке окружения написано в официальной документации.

Dart

import 'package:flutter/material.dart'; void main() => runApp(MyApp());

В мире Android-разработки используется Java, а с недавнего времени и Kotlin. Первое что бросается в глаза при виде Flutter-приложений — непривычный код.

Google позиционирует его как альтернативу JavaScript со строгой типизацией, высокой производительностью и гибкостью. Теперь в одном ряду с ними стоит Dart.

Возможно, это дело вкуса и привычки. Синтаксис Dart прост в освоении, хотя и не так красив как у Kotlin.

Создание проекта

Проект можно создать, выполнив в консоли команду flutter create name или используя IDE (в Android Studio → New Flutter Project).

Структура приложения

В корневой директории приложения есть четыре пакета — lib, ios, android и test. После создания проекта вы увидите следующую структуру.

Там располагаются все dart-файлы и основной код приложения. Первая — директория фреймворка. Кроме того, можно встроить Flutter в уже существующее приложение. Несмотря на то, что Flutter компилируется в нативный код, для каждой из платформ приходится писать некоторые нативные взаимодействия. В пакете test найдете тесты. Для нативного кода предусмотрены два пакета — ios/android, в которых есть возможность писать на привычном для конкретной платформы языке — Obj-C/Swift или Java/Kotlin.

Если говорить об аналогии, то для Flutter’а это, как build.gradle (он тоже есть, но уже в нативной Android части). В корневой директории есть файл конфигурации pubspec.yaml — там подключаются библиотеки и т.д.

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

У приложения единая точка входа — метод main. В вашем проекте сразу будет файл main.dart, содержащий код с примером. Он отвечает за создание корневого виджета.

Everything is a Widget

Любая сущность пользовательского интерфейса — виджет. Все, что вы видите (или не видите) на экране, все, с чем происходит взаимодействие и само приложение — виджеты. Приложение построено из них, как конструктор. Текстовое поле, отступ или детектор жестов — виджеты.

Согласно официальному сайту, “каждый виджет является неизменяемым описанием части пользовательского интерфейса”.

Для примера построим приложение с таким экраном:

Здесь присутствуют следующие виджеты:

  • приложение
  • экран
  • AppBar
  • текст
  • кнопка с лоадером

Часть из них реализована в фреймворке, часть необходимо составить самим из готовых деталей.

Первые статичны (например, текст), вторые поддерживают изменение состояния (например, экран). Виджеты бывают двух типов Stateless и Stateful.

Stateless

Это корень приложения. Примером такого виджета в приложении может быть MyApp. Внутри разместим все, что требуется для отрисовки с помощью метода build.

class MyApp extends StatelessWidget }

Вам всего лишь необходимо переопределить метод build, а в нем собрать необходимый элемент. Любой статичный виджет — наследник класса StatelessWidget. Для создания нового элемента не следует расширять уже существующий. Flutter пропагандирует композицию.

В примере данный виджет строится из MaterialApp (корень приложения, основанного на компонентах из MaterialDesign), внутри которого лежит Scaffold — это экран.

В данном случае он имеет состояние. MyHomePage — тоже виджет, который отрисовывает тело экрана, исключая AppBar. О нем поговорим ниже.

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

Замечание: слово new в Dart, начиная со второй версии, опционально.

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

Statefull

Чтобы сделать такой виджет необходимо наследоваться от StatefullWidgetи создать класс-наследник State<T>, который является состоянием виджета и отвечает за то, что пользователь увидит на экране смартфона. Виджеты с состоянием поддерживают перерисовку при изменении их состояния (State).

Внутри можно, например, задать другой цвет фона кнопки, и фреймворк сам определит минимально необходимую перерисовку UI. Изменение состояния виджета происходит через вызов метода setState() {}.

Оно хранит _name — имя, которое будет выводится в текстовом блоке, и флаг загрузки _isLoading (отвечает за то, как будет отрисован внутренний виджет LoadingButton; пример управления состоянием через родителя). В моем случае главная страница MyHomePage будет виджетом с состоянием.

class _MyHomePageState extends State<MyHomePage> { String _name = ""; bool _isLoading = false; @override Widget build(BuildContext context) => Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: EdgeInsets.all(16.0), child: Text( '$_name', ), ), LoadingButton( isLoading: _isLoading, action: _generateName, ) ], ), ); }

Замечу, что в Dart нет модификаторов доступа, типа private и public. У кнопки есть коллбек, action, куда подается метод _generateName(). Но если необходимо сделать приватным что-либо внутри модуля, то наименование должно начинаться с префикса “_”.

Он отвечает за загрузку имени, изменяет флаг isLoading и устанавливает значение name, что приводит к перерисовке кнопки и текста. Метод _generateName асинхронный.

final snack = SnackBar(content: Text("Handle error!")); _generateName() async { toggleLoading(); try { //загрузка данных через await //парсинг Json setName(map["name"]); toggleLoading(); } catch (e) { setName("oops!"); Scaffold.of(context).showSnackBar(snack); toggleLoading(); } } void toggleLoading() { setState(() { _isLoading = !_isLoading; }); }

Без этого вызова виджет просто не будет перерисован. Для изменения состояния обязательно нужно вызвать setState() {}.

В момент перерисовки подставляется либо текст, либо индикатор в кнопку. Реализация лоадера оказалась довольно простой.

Реализация занимает всего несколько строк

_buildButtonChild() { if (isLoading) { return Transform.scale( scale: 0.5, child: CircularProgressIndicator(), ); } else { return Text("Click for name"); } }

Transform.scale нужен, чтобы уменьшить размер.

Подробнее можно посмотреть здесь, здесь и здесь. Асинхронное взаимодействие в Flutter, собственно как и в Dart, основано на async-await.

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

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

Уроки разбиты на две главы, вдумчивое прохождение каждой из которых займёт 3-4 часа. Хороший пример базового курса по Flutter — курс на Udacity.

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

Заключение

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

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть