Про Flutter, кратко: Основы


После доклада Юры Лучанинова, я решил для себя попробовать Flutter. Чтобы мозг размять, и чтобы было о чем похоливарить с мужиками на кухне. Дело пошло. Я начал смотреть, потом читать, потом писать. И вроде все получается, приложения запускаются, и то что объясняют — понятно, все просто. Но не без “но” — объясняют не все. А поскольку платформа, ЯП, подходы и даже предметная область для меня новые, то подобное вызывает раздражение, ведь у тебя “не запускается”, а ты даже не знаешь что гуглить: Dart/Flutter/Window/Screen/Route/Widget?


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


Про гайд


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


Писать я буду с перспективы веб-разработчика. Большинство из вас скорее всего знакомо со стэком веба, а аналогия со знакомой платформой лучше аналогии с постройкой домов или чего там еще, Animal, Dog, Foo, Bar…


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


Про платформу


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


  • В отличии от многих известных на сегодняшний день мобильных платформ, Flutter не использует JavaScript ни в каком виде. В качестве языка программирования для Flutter выбрали Dart, который компилируется в бинарный код, за счет чего достигается скорость выполнения операций сравнимая с Objective-C, Swift, Java, или Kotlin.
  • Flutter не использует нативные компоненты, опять же, ни в каком виде, так что не приходится писать никаких прослоек для коммуникации с ними. Вместо этого, подобно игровым движкам (а вы ведь знаете что у игр очень динамичный UI), он отрисовывает весь интерфейс самостоятельно. Кнопки, текст, медиа-элементы, фон — все это отрисовывается внутри графического движка в самом Flutter. После вышесказанного стоит отметить, что “Hello World” приложение на Flutter занимает совсем немного места: iOS ? 2.5Mb и Android ? 4Mb.
  • Для построения UI во Flutter используется декларативный подход, вдохновленный веб-фреймворком ReactJS, на основе виджетов (в мире веба именуемых компонентами). Для еще большего прироста в скорости работы интерфейса виджеты перерисовываются по необходимости — только когда в них что-то изменилось (подобно тому как это делает Virtual DOM в мире веб-фронтенда).
  • В дополнение ко всему, в фреймворк встроен Hot-reload, такой привычный для веба, и до сих пор отсутствовавший в нативных платформах.

О практической пользе этих факторов я очень рекомендую прочитать статью Android разработчика, который переписал свое приложение с Java на Dart и поделившегося своими впечатлениями. Сюда я лишь вынесу названное им количество файлов/строк кода до (написанное на Java) — 179/12176, и после (переписанное на Dart) — 31/1735. В документации можно найти подробное описание технических особенностей платформы. А вот ещё ссылка, если интересно посмотреть другие примеры работающих приложений.


Про Dart


Dart — язык программирования на котором нам предстоит писать приложения под Flutter. Он очень прост, и если у вас есть опыт работы с Java или JavaScript, вы быстро его освоите.


Я пытался написать обзорную статью о Dart, стремясь описать лишь необходимый минимум для изучения Flutter. Но в этом языке столько нюансов, что несмотря на несколько попыток написать такую статью, у меня так и не удалось сделать ее достаточно полной и в то же время короткой. С другой стороны, авторы A Tour of the Dart Language отлично справились с этой задачей.


Про подготовку


Эта тема, как и Dart, очень хорошо описана в официальном гайде. Я мог бы разве что скопировать ее сюда, но делать этого не стану.


Ничего не дожидаясь, идем на страницу гайда по установке, выбираем платформу и по шагам выполняем инструкцию для установки платформы на нашу систему. В своем редакторе обязательно подключаем плагины. В том же гайде есть инструкция по настройке VS Code и IntelliJ. Для вашего редактора тоже найдутся плагины для Dart и Flutter (обычно нужно ставить два). Запускаем приложение и проверяем его работоспособность.


Подсказка для пользователей OSX. Мне жалко места занимаемого нарисованными рамками телефона в эмуляторе iOS, поэтому я их отключил и переключился на iPhone 8 (он не такой “длинный”):


  • Hardware > Device > iOS # > iPhone 8
  • Window > Show Device Bezels

Без кнопок жить можно, ведь есть хоткеи: Shift + Cmd + H — это домой, Cmd + Right — а это перевернуть телефон, остальное можно найти в меню Hardware. А вот экранную клавиатуру я советую включить, ведь важно понимать можно ли работать с приложением когда половина экрана регулярно перекрывается клавиатурой: Cmd + K (работает когда фокус находится на каком-то поле ввода).


iPhone 8 & iPhone X с рамками
iPhone 8 & iPhone X с рамками


iPhone 8 & iPhone X без рамок
iPhone 8 & iPhone X без рамок


Про структуру


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


  • lib/ — По принципам pub (менеджер пакетов Dart’а) весь код лежит в этой подпапке;
  • pubspec.yml — сюда записываются зависимости приложения, которые нужно установить для его запуска, точно как package.json, но есть нюанс, устанавливать их нужно не через стандартную утилиту Dart’а, о которой говорилось выше, а через команду Flutter’а: flutter pub get <package_name>;
  • test/ — вы ведь знаете что там? Запустить их можно вызвав flutter test;
  • ios/ & android/ — папки с настройками для каждой из платформ, там указывается какие права нужны для запуска приложения (доступ к локации, bluetooth), иконочки и все что специфично для платформы.

Со структурой разобрались, заходим в папку lib/ где нас ждет main.dart файл. Это, как вы можете догадаться, тот самый файл в котором мы должны запускать наше приложение. А запускается оно подобно как в языке C (и еще тонны других) вызовом функции main().


Про виджеты (Hello World здесь)


Во Flutter’е все построено на Widget’ах: тут и вьюшки, и стили с темами, и состояние в виджетах хранится. Есть два основных типа виджетов: со стейтом и без, но пока не об этом. Давайте с простого.


Удаляем все из main.dart. Вставляем следующий код внимательно вчитываясь в комментарии:


import 'package:flutter/widgets.dart'; // подключаем базовый набор виджетов

// Когда Dart запускает приложение он вызывает функцию main()
main() => runApp( // а функция runApp запускает Flutter
  Text( // этот виджет, он отрисовывает текст, такой себе <span>
    'Hello, World!!!', // первый аргумент — текст который нужно отобразить
    textDirection: TextDirection.ltr, // а здесь мы указываем направление текста
  ),
);

runApp(…) принимает единственный аргумент — виджет, который будет корневым для всего проекта. Кстати, его изменения Hot-reload подхватить не может, так что нужно будет перезапускать приложение.
Text(…) — Flutter не может просто отобразить строку на экране. Для вывода текста необходимо указать Text. textDirection. И это не выравнивание текста вроде text-align, если сравнивать с вебом, то это аналог direction. Часть API для интернационализации приложения. Text не заработает, пока не будет знать направление, но указывать его везде не придется — дальше мы разберем как настроить направление текста для всего приложения.


Уже запустили приложение? “Hello, World!” вывелся! Вроде бы… Да? Но что-то явно пошло не так.


Скриншот запущенного приложения


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


import 'package:flutter/widgets.dart';

main() => runApp(
  Center( // виджет, который выравнивает содержимое по центру
    child: Text(
      'Hello, World!',
      textDirection: TextDirection.ltr,
    ),
  ),
);

Center(…) — это виджет который позволяет разместить другой виджет, переданный в аргументе child, в центре по горизонтали и вертикали. Вы часто будете встречать child и children в приложениях Flutter, так как практически все виджеты используют эти имена для передачи виджетов, которые должны быть отрисованы внутри вызываемого виджета.


Композиции виджетов используются в Flutter для отрисовки UI, изменения внешнего вида, и даже для передачи данных. К примеру виджет Directionality(…) задает направление текста для всех дочерних виджетов:


import 'package:flutter/widgets.dart';

main() => runApp(
  Directionality(
    textDirection: TextDirection.ltr,
    child: Center(
      child: Text('Hello, World!'),
    ),
  ),
);

Посмотрим на еще один очень важный виджет и заодно преобразим внешний вид нашего приложения:


import 'package:flutter/widgets.dart';

main() => runApp(
  Directionality(
    textDirection: TextDirection.ltr,
    child: Container( // новый виджет! <div> в мире Flutter'а
      // Для виджета Container свойство color означает цвет фона
      color: Color(0xFF444444),
      child: Center(
        child: Text(
          'Hello, World!',
          style: TextStyle( // а у текста появился виджет, который его стилизует
            color: Color(0xFFFD620A), // задаем ему цвет текста
            fontSize: 32.0, // и размер шрифта
          ),
        ),
      ),
    ),
  ),
);

Скриншот HelloWorld приложения


Color(…) — цвет. В документации указаны разные способы его задания, но основным является просто передача числа в конструктор класса. В примере выше мы передаем конструктору число, записанное в шестнадцетиричной форме, что очень похоже на HEX, только вначале у нас добавилось еще два знака, означающих степень прозрачности цвета, где 0x00 — это абсолютно прозрачный, а 0xFF — это совсем не прозрачный.


TextStyle(…) — еще более интересный виджет, с его помощью можно задать цвет, размер, толщину, межстрочный интервал, добавить подчеркивание и прочее.


Приложение на Flutter написано, дело сделано! В доках можно почитать как его собрать под Android и iOS, там же есть ссылочки чтобы вы узнали как его отправить в нужный Store. Кому этого мало, я ниже накидал еще пару строк про Flutter, может больше…


Про Stateless виджеты


Как использовать виджеты — мы разобрались, давайте теперь разбираться как их создавать. Выше уже упоминалось, что есть виджеты у которых есть состояние, и у которых его нет. До сих пор мы использовали только виджеты без состояния. Это не значит, что у них его совсем нет, ведь виджеты это просто классы, и их свойства могут быть изменены. Просто после того, как виджет будет отрисован — изменения его состояния не приведет к обновлению этого виджета в UI. К примеру, если нам нужно поменять текст на экране, нужно будет сгенерировать другой виджет Text и указать новое содержимое которое мы хотим отобразить. Такие виджеты можно назвать константными, если вы понимаете о чем я. И они простые, поэтому с них и начнем.


Чтобы создать Stateless виджет, нужно:


  1. Придумать красивое имя для нового класса;
  2. Унаследовать класс от StatelessWidget;
  3. Реализовать метод build(), который принимает BuildContext в качестве аргумента и возвращает какой-нибудь Widget.

import 'package:flutter/widgets.dart';

main() => runApp(
  Directionality(
    textDirection: TextDirection.ltr,
    child: Center(
      child: MyStatelessWidget()
    ),
  ),
);

class MyStatelessWidget extends StatelessWidget {
  // аннотация @override нужна для оптимизации, используя ее мы говорим,
  // что переопределенный метод из родительского класса мы использовать
  // не будем, так что компилятор может его выбросить
  @override
  Widget build(BuildContext context) { // [context] будет описан позже
    return Text('Hello!');
  }
}

Пример виджета с одним аргументом:


// …

class MyStatelessWidget extends StatelessWidget {
  // Все свойства Stateless виджета должны быть объявлены с final, или с const
  final String name; // обычное свойство
  MyStatelessWidget(this.name); // обычный конструктор

  @override
  Widget build(BuildContext context) { // [context] будет описан еще ниже
    return Text('Hello, $name!');
  }
}

Про Stateless больше и добавить нечего…


Про Hot Reload


Обратите внимание, что при изменении содержимого нашего виджета приложение будет автоматически перерисовываться. После того, как мы вынесли виджет из функции main() Hot-reload стал нам помогать.


Важно также понимать, что из-за запущенного модуля для горячей замены приложение работает на порядок медленнее.


Про GestureDetector


GestureDetector виджет в действии


В следующей секции мы будем разбираться с StatefulWidget (с виджетами которые изменяются при изменении их состояния). Для того чтобы это было интересно, нам нужно это состояние как-то изменять, согласны? Мы будем изменять состояние виджета реагируя на касания по экрану. Для этого мы будем использовать GestureDetector(…) — виджет, который ничего не отрисовывает, но следит за касаниями на экране смартфона и сообщает об этом вызывая переданные ему функции.


Создадим кнопку в центре экрана, при нажатии на которую в консоль будет выводиться сообщение:


import 'package:flutter/widgets.dart';

main() => runApp(
  Directionality(
    textDirection: TextDirection.ltr,
    child: Container(
      color: Color(0xFFFFFFFF),
      child: App(),
    ),
  ),
);

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: GestureDetector( // используется как обычный виджет
        onTap: () { // одно из свойств GestureDetector
          // Этот метод будет вызван, когда дочерний элемент будет нажат
          print('You pressed me');
        },
        child: Container( // нашей кнопкой будет контейнер
          decoration: BoxDecoration( // стилизуем контейнер
            shape: BoxShape.circle, // зададим ему круглую форму
            color: Color(0xFF17A2B8), // и покрасим его в синий
          ),
          width: 80.0,
          height: 80.0,
        ),
      ),
    );
  }
}

Нажимаем на синюю кнопку и видим сообщение в консоли. Нажимаем еще раз и снова видим сообщение в консоли. Еще раз… Ладно, хватит залипать.


Про Stateful виджеты


StatefulWidget — простые, даже проще чем StatelessWidget'ы. Но есть нюанс: они не существуют сами по себе, для их работы нужен еще один класс который будет хранить состояние этого виджета. При этом, его визуальная часть (виджеты из которых он состоит) также становятся его состоянием.


Для начала, посмотрим на класс виджета:


// …

class Counter extends StatefulWidget {
  // Изменяемое состояние хранится не в виджете, а внутри объекта особого класса,
  // создаваемого методом createState()
  @override
  State<Counter> createState() => _CounterState();
  // Результатом функции является не просто объект класса State,
  // а обязательно State<ИмяНашегоВиджета>
}

Выше мы создали “пустой” виджет, который реализовал очень простой метод createState(). Такое разделение презентации и состояния позволяет Flutter’у сильно оптимизировать работу приложения.


Объект состояния совершенно не сложный. Более того, он практически идентичен StatelessWidget'ам написанным нами выше. Его основное отличие — родительский класс.


// …

class _CounterState extends State<Counter> {
  // Внутри него мы наконец-то можем объявить динамические переменные,
  // в которых мы будем хранить состояние.

  // В данном случае, это счетчик количества нажатий
  int counter = 0;

  // А дальше все очень просто, мы имплементируем точно такой же метод
  // для отрисовки виджетов, который мы использовали в классе Stateless виджета.
  @override
  Widget build(BuildContext context) {
    // И тут практически ничего не изменилось с нашего последнего примера,
    // а то что изменилось — я прокомментировал:
    return Center(
      child: GestureDetector(
        onTap: () {
          // В момент, когда кнопка нажата, мы увеличиваем значение
          // перменной counter.
          setState(() {
            // setState() необходим для того, чтобы вызвать методы
            // жизненного цикла виджета и сказать ему, что пора обновится
            ++counter;
          });
        },
        child: Container(
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: Color(0xFF17A2B8),
          ),
          width: 80.0,
          child: Center(
            child: Text( // выводим значение свойства counter
              '$counter', // чтобы следить за его изменением
              style: TextStyle(fontSize: 30.0),
            ),
          ),
        ),
      ),
    );
  }
}

Работающее Counter приложение


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


Какое замечательное приложение мы с вами сделали! Это отличный результат. Но перед тем как закончить эту часть курса, давайте рассмотрим еще пару интересных виджетов. Только в этот раз мы напишем больше кода, просто, чтобы было интереснее. Большая часть приложения должна быть вам знакома, а остальное вы уже должны были научиться понимать:


import 'package:flutter/widgets.dart';

main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.ltr,
      child: Container(
        padding: EdgeInsets.symmetric(
          vertical: 60.0,
          horizontal: 20.0,
        ),
        color: Color(0xFFFFFFFF),
        child: Content(),
      ),
    );
  }
}

class Content extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Counter('Manchester United'),
        Counter('Juventus'),
      ],
    );
  }
}

class Counter extends StatefulWidget {
  final String _name;
  Counter(this._name);

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(bottom: 10.0),
      padding: EdgeInsets.all(4.0),
      decoration: BoxDecoration(
        border: Border.all(color: Color(0xFFFD6A02)),
        borderRadius: BorderRadius.circular(4.0),
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          // widget — это свойство класса State, в котором хранится
          // ссылка на объект создавший текущий стейт, то есть на наш виджет
          _CounterLabel(widget._name),
          _CounterButton(
            count,
            onPressed: () {
              setState(() {
                ++count;
              });
            },
          ),
        ],
      ),
    );
  }
}

class _CounterLabel extends StatelessWidget {
  static const textStyle = TextStyle(
    color: Color(0xFF000000),
    fontSize: 26.0,
  );

  final String _label;
  _CounterLabel(this._label);

  @override
  Widget build(BuildContext context) {
    return Text(
      _label,
      style: _CounterLabel.textStyle,
    );
  }
}

class _CounterButton extends StatelessWidget {
  final _count;
  final _onPressed;
  _CounterButton(this._count, {@required this._onPressed});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        _onPressed();
      },
      child: Container(
        padding: EdgeInsets.symmetric(horizontal: 6.0),
        decoration: BoxDecoration(
          color: Color(0xFFFD6A02),
          borderRadius: BorderRadius.circular(4.0),
        ),
        child: Center(
          child: Text(
            '$_count',
            style: TextStyle(fontSize: 20.0),
          ),
        ),
      ),
    );
  }
}

Еще одно Counter приложение на Flutter


У нас появилось два новых виджета: Column() и Row(). Попробуйте сами догадаться, что они делают. А в следующей статье мы рассмотрим их подробнее, а также посмотрим еще не один виджет позволяющий компоновать вместе другие виджеты, и создадим симпатичное приложение используя Flutter библиотеку называющуюся Material.


Про домашнее задание


Если вам хочется почитать что-нибудь еще на досуге, вот список интересных ссылок:


Комментарии (35)


  1. saag
    24.11.2018 14:44
    +1

    Таки Гугл кинет всех с Андроидом в 23-м году? И «Все на Фуксию!»:-) Надо будет почитать про flutter.


    1. barkalov
      24.11.2018 15:14

      А потом, в 26-м «Все на Герань!». Только недавно начал себя более менее уверенно чувствовать в Angular (после довольно плотной работы с Angular.js)… А уже и vue на пятки наступает, и react&redux сбоку толкается. Теперь вот ещё Polymer да dart с flutter'om.

      Фронтендер, как вечный новичок в этом непостоянном мире. Никакого спокойствия.


      1. FlamyXD
        25.11.2018 20:35

        Это конкуренция, которая в итоге приведет к лучшей технологии.


  1. irbis_al
    24.11.2018 15:03

    Я вот тоже изучаю flutter.
    Писать наверное удобнее всего на нем UI(Во всяком случае для меня)
    Но вот он жутко тормознутый… я об этом писал в других топиках про flutter на хабре, но с тех пор впечатление о тормознутости только усилилось.


    1. HotIceCream
      24.11.2018 15:20

      В релизной сборке? И на какой версии системы?


      1. irbis_al
        24.11.2018 15:55

        flutter doctor
        Doctor summary (to see all details, run flutter doctor -v):
        [?] Flutter (Channel beta, v0.8.2, on Linux, locale ru_RU.utf8)
        [!] Android toolchain - develop for Android devices (Android SDK 27.0.3)
            ? Android license status unknown.
        [?] Android Studio (version 3.0)

        Ну вот такое окружение.


        1. HotIceCream
          24.11.2018 15:59

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

          Про версию системы я не корректно выразился. Я хотел узнать про версию Android\ios. Слышал, что на 4 Android может лагать.

          Сам я на эмуляторе с 8 Android, на ios симуляторах, на реальном устройстве с 8 Android лагов не встречал даже на дебажной сборке.


          1. irbis_al
            24.11.2018 16:14
            +2

            Да это дебажная сборка… релизная не сильно отличается по скорости.
            А вот в моем опыте Android 4 работает лучше чем 5 й.(причем 5й по железу лучше)
            6й также как 4 й работает.Я не проверял на 8м но дело в том, что всё относительно… я разрабатываю на java. И вот думаю… а повторю что-то на flutter… и отличия по производительности огромные.Ладно я смерился что apk в 12 раз больше… ладно оперативки в 10 раз больше потребляет… Но слишком медленно… Да… возможно нет ещё опыта (и возможно криворукий)… но беру примеры, в группе samples что сам flutter предлагает к изучению.(и там есть что-то подобное задачки) и вот эти рекомендованные, сделанные специалистами. тоже тормозят


          1. atomAltera
            24.11.2018 22:38

            Ну я вот собрал релизную сборку Startup Name Generator из офф доков и она по сравнению с дебаг версией работает сильно лучше (на iOS)


    1. Drag13
      24.11.2018 15:35

      А что значит тормознутый? Лагает само приложение или какие то проблемы в процессе разработки? Какое железо?


  1. Focushift
    24.11.2018 15:49
    +2

    Я не понимаю, как может быть удобным это месиво элементов стилей и значений текстовой строки?
    Про привыкание не надо, зачем привыкать, скажем, к кровати без матраса?


    1. HeaTTheatR
      24.11.2018 16:05
      +1

      Согласен на все 100% — код на Flutter безобразен и хаотичен! Просто не понятно, как обычные два текстовых поля могут занимать 118 строк кода, который представляет собой ужаснейшую кашу?!


      1. termosa Автор
        24.11.2018 20:50

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

        Это конечно же не все. Смешивание данных и отображения тоже является плохим подходом. Дальше я постараюсь показать как разделить эти две сущности. И даже то, как вынести стилизацию — в Flutter это очень простая задача (не в сравнении с веб, но в сравнении с другими нативными или околонативными решениями).


    1. irbis_al
      24.11.2018 16:21
      +2

      Вот мне наоборот ближе именно flutter.По java мне наоборот не нравится, что файлы логики и кода разбросаны.И сделать красивый насыщенный дизайн на java непросто.И flutter он очень продуман писать на нем UI… И можно быстро получить хороший дизайн(Почти как в вебе).Это меня и подкупило.Вот в примерах есть сложные интерфейсы и просто изящный дизайн.И смотря код… там оно просто как будто сделано «мимоходом»,-играючи… Поднять такое на java или kotlin будет весьма непросто и точно не играючи.Если бы не его тормознутость.


      1. HeaTTheatR
        24.11.2018 16:58

        И смотря код… там оно просто как будто сделано «мимоходом»,-играючи…

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


        1. irbis_al
          24.11.2018 17:27

          Там почти такая же парадигма(техническая философия) как и React.
          После React довольно легко привыкнуть, хотя это индивидуально.За эти внешние неудобства кода следует некоторая бонусная «оплата»… Много разных кнопок на любой вкус, легко делать градиенты, отступы, нахлесты, вертикальный скролинг(или как его называют ) sliding(слайдинг), закругления, отдельные темы,- всё просто делается из коробки.Т.е можно получить насыщенный интерфейс как в вебе.На java(kotlin) это на порядок сложнее.


          1. HeaTTheatR
            24.11.2018 17:38
            -1

            После React довольно легко привыкнуть

            К такому нельзя привыкнуть.


            Много разных кнопок на любой вкус, легко делать градиенты, отступы, нахлесты, вертикальный скролинг(или как его называют ) sliding(слайдинг), закругления, отдельные темы

            Это можно сделать везде, это отнюдь не плюсы.


  1. Alex_ME
    24.11.2018 16:15

    Описывать UI не на декларативном DSL, а на обычно ЯП, да еще с довольно громоздким синтаксисом. Куча скобочек и всего этого. Это выглядит довольно громоздко и неудобно.


    1. Vilyx
      25.11.2018 03:14
      +1

      Я раньше тоже так думал, но на самом деле оказалось в некоторых моментах даже удобнее. Веселее всего когда хочется сделать UI зависимым от условий. В декларативном стиле впихиваются свои специальные конструкции, а здесь пишешь как писал. Когда есть визуальная среда разработки интерфейса(компонентики накидывать), тогда вообще нет никакой разницы что там под капотом. Непривычно писать интерфейс кодом обычного ЯП, но быстро привыкаешь всё повторяющееся выделять в отдельные компоненты(функции) и в итоге получается даже компактнее и красивее чем в декларативных языках.


      1. Alex_ME
        26.11.2018 10:04

        В декларативном стиле впихиваются свои специальные конструкции, а здесь пишешь как писал.

        Ну вроде, у реакта такая же фишка. Особо своего DSL нет, пишешь на JS. Но разметка-то все же на HTML JSX.


  1. Mox
    24.11.2018 16:45
    +1

    Этим летом я попробовал Flutter — для сравнения с RN

    Качество реализации мне понравилось гораздо больше, чем React Native
    А вот впечатления от Dart, от того как сделано управление состояниями, и как сделано построение UI. После react-native и react-redux -это какая-то дичь, будет жаль если так и останется.

    Правда для redux я тоже использую reduxsauce и redux-saga, может быть появяться какие-то библиотеки, которые сделают кодинг более кратким и приятным.


    1. termosa Автор
      25.11.2018 21:01

      Главное не забивать гвозди раньше времени. Flutter до сих пор не выкатил первую версию.

      Интересно, что именно не понравилось в управлении состоянием? Хранение состояние внутри виджета? Использование setState для обновления?

      У Flutter только недавно появился InheritedModel в добавок к InheritedWidget.

      А коммьюнити только начинает решать существующие проблемы и перетаскивать хорошие решения на платформу, в том числе и redux-подобные.


  1. GroGo
    24.11.2018 18:02

    А есть какая-либо информация, сколько места занимает на диске среда для разработки? Например, у меня есть ноутбук с небольшим жестким диском — 120Гб. Сколько места у меня останется на диске после установки всего нужного, что описано на странице(Допустим под MAC OS) flutter.io/docs/get-started/install?


    1. shanlove
      24.11.2018 20:33

      Сама папка с флаттером у меня 1Гб (мак). Может оно еще где что по-мелочам оставляет. Но по сравнению с икскодом и андроидстудио + сдк — копейки.


    1. termosa Автор
      24.11.2018 20:39

      XCode занимает где-то под 6гб, и Flutter 300мб + кеш (у меня сейчас 600мб)


  1. Agranatmark
    25.11.2018 00:14

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


    1. termosa Автор
      25.11.2018 02:57

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

      В основе Flutter графический движок используемый в браузере Chrome, который себя уже давно хорошо зарекомендовал. Он легко выполняют свою работу не проваливаясь ниже 60fps.

      В добавок к этому виджеты Flutter интересным образом оптимизированы. Вот, к примеру, трюк со списком из списков (1000х1000 элементов). Отрисовывается и отлично работает даже в development режиме с включенным Hot-reload. И продолжает так же хорошо работать при увеличении каждого списка в 10 раз. (MacBook Pro 2015, 16гб, версия без видюхи)

      тяжелая гифка
      image


  1. Nookie-Grey
    25.11.2018 12:04
    +2

    Читать документацию времени нет, а писать очередную статью про основы есть? :D


    1. termosa Автор
      25.11.2018 12:38

      (: Да, звучит не логично.

      Дело в том, что я не занимаюсь мобильной разработкой, и в ближайшее время не планирую ею заниматься. Но меня очень заинтересовал Flutter и мне захотелось разобраться с ним.

      Записывать — это один из способов лучше запомнить, а объяснять — лучший способ разобраться, ведь так? )


      1. Nookie-Grey
        25.11.2018 16:53

        Абсолютно согласен) Сам это практикую :D


      1. Borz
        25.11.2018 19:36

        здесь должен быть анекдот про Достоевского и чукчу


  1. IvanNochnoy
    25.11.2018 14:07
    +2

    Интересна эта платформа своей простотой сравнимой с разработкой веб-приложений

    Именно этого я и боялся.


  1. vt4a2h
    25.11.2018 22:10

    Есть ли какие приемущества перед Qt (QML) для мобильных устройств? Пока я вижу довольно зашумлённый синтаксис и странную «декларативность» языка…


    1. HeaTTheatR
      25.11.2018 23:23

      Лучше, чем QML и Kivy Language нет ничего в плане описания UI за последние 1000 лет!