39
7 Оглавление Об авторе 12 О техническом рецензенте (обозревателе) 13 О переводе 14 Благодарности 15 Введение 16 ГЛАВА 1 18 FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ18 Медитации над бездной 18 Что за (глупое) название?19 Dart: Язык богов? 21 Виджеты окружают! 23 Ближе к делу: плюсы и Минусы Flutter 27 Хватит болтать, начинаем практику с Flutter! 30 Flutter SDK30 Android Studio 31 Типичное приложение «Hello, World!» 32 Горячая перезагрузка: вот что я люблю! 40 Базовая структура приложения Flutter 42 Еще парочка моментов «под прикрытием» 44 Итого 45 ГЛАВА 2 46 МГНОВЕННОЕ РУКОВОДСТВО ПО DART 46 Вещи, которые вы должны знать 46 Все о комментариях – без лишних комментариев 47 Все меняется: переменные 49 Ну он и тип типы данных 51 Перечисления – если одного значения мало! 56 А ты его точно знаешь? Ключевые слова «as» и «is» 57 Плыть по течению: управление логикой потока команд57 Больше, чем ничто: void59 Операторы60 Коротко про ООП в Dart 63 Кое-что о функциях 71 Что такое Assertions 74

Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

  • Upload
    others

  • View
    9

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

7

Оглавление

Об авторе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

О техническом рецензенте (обозревателе) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

О переводе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

Благодарности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

Введение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

ГЛАВА 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

Медитации над бездной . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18Что за (глупое) название? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19Dart: Язык богов? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21Виджеты окружают! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23Ближе к делу: плюсы и Минусы Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27Хватит болтать, начинаем практику с Flutter! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

Flutter SDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30Android Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

Типичное приложение «Hello, World!» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32Горячая перезагрузка: вот что я люблю! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40Базовая структура приложения Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42Еще парочка моментов «под прикрытием» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44Итого . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

ГЛАВА 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

МГНОВЕННОЕ РУКОВОДСТВО ПО DART . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

Вещи, которые вы должны знать . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46Все о комментариях – без лишних комментариев . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47Все меняется: переменные . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49Ну он и тип . . . типы данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51Перечисления – если одного значения мало! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56А ты его точно знаешь? Ключевые слова «as» и «is» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .57Плыть по течению: управление логикой потока команд . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .57Больше, чем ничто: void . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59Операторы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60Коротко про ООП в Dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63Кое-что о функциях . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71Что такое Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

Page 2: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

8

Вне времени: асинхронность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74Тсс, тихо! Библиотеки (и видимость) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75Для тебя я сделаю исключение: обработка исключений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .77У меня есть сила: генераторы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78Мета-Dart: метаданные . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80Пообобщаемся? Дженерики, или обобщения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

Подведем итоги . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

ГЛАВА 3 СКАЖИ ПРИВЕТ МОЕМУ МАЛЕНЬКОМУ ДРУГУ FLUTTER: ЧАСТЬ I . . . . . . . . . . . . . . . . . . . . . . 83

Набор виджетов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83Layout (Компоновка) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83Навигация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94Ввод данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103Диалоговые и всплывающие окна . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

Подведем итоги главы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

ГЛАВА 4 СКАЖИ ПРИВЕТ МОЕМУ МАЛЕНЬКОМУ ДРУГУ FLUTTER . ЧАСТЬ II . . . . . . . . . . . . . . . . . . . . .123

Виджеты стиля . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123Theme и ThemeData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124Opacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125DecoratedBox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125Transform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

Анимации и переходы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127AnimatedContainer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127AnimatedCrossFade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128AnimatedDefaultTextStyle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130Несколько других: AnimatedOpacity, AnimatedPosition, PositionTransition, SlideTransition, AnimatedSize, ScaleTransition, SizeTransition и RotationTransition . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

Drag и Drop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131Просмотр данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133DataTable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135GridView . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137ListView и ListTile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

Остальные виджеты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140CircularProgressIndicator (CupertinoActivityIndicator) и LinearProgressIndicator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141Icon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143Chip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145FloatingActionButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146PopupMenuButton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

Базовые библиотеки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149Основные библиотеки фреймворка Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

Page 3: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

9

Библиотеки Dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153Вспомогательные библиотеки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

Итого . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

ГЛАВА 5 FLUTTERBOOK . ЧАСТЬ I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .158

Что мы делаем? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158Старт проекта . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160Конфигурации и библиотеки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161Структура UI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162Структура кода приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163Отправная точка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163Глобальные утилиты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166Управление состоянием . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168Начнем с простого: заметки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

Точка отсчета: Notes .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172Модель: NotesModel .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174Слой базы данных: NotesDBWorker .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175Экран списка: NotesList .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179Экран ввода: NotesEntry .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

Что в итоге . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

ГЛАВА 6 FLUTTERBOOK . ЧАСТЬ II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .192

Сделаем это: задачи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192TasksModel .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192TasksDBWorker .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193Tasks .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193TasksList .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193TasksEntry .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196

Назначим свидание: Appointments (Встречи) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197AppointmentsModel .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197AppointmentsDBWorker .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198Appointments .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198AppointementsList .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198AppointmentsEntry .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

Как с вами связаться: контакты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206ContactsModel .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206ContactsDBWorker .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207Contacts .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207ContactsList .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207ContactsEntry .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

Подведем итоги . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

ГЛАВА 7 FLUTTERCHAT . ЧАСТЬ I: СЕРВЕР . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .218

Можем ли мы это построить? Да, мы можем! Но . . . что «это»?! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218

Page 4: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

10

Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219Сохранение линий связи открытыми: socket .io . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222Код сервера FlutterChat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226

Два Bits of State и Object заходят в Bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227Поймай меня, если сможешь: сообщения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228Заходим в парадную дверь: проверка пользователей . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229

Итого . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238

ГЛАВА 8 FLUTTERCHAT . ЧАСТЬ II: КЛИЕНТ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .239

Model .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239Connector .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242

Связанные с сервером функции сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245Связанные с клиентом обработчики сообщений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246

main .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249LoginDialog .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252

Вход для существующих пользователей . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255Home .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257AppDrawer .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258Lobby .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260CreateRoom .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264

Строим форму . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266UserList .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268Room .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271

Меню . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272Содержимое главного экрана . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275Приглашение или исключение пользователей . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278

Итого . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281

ГЛАВА 9 FLUTTERHERO: ИГРА FLUTTER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .282

История такова . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282Базовая компоновка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283Структура каталога и исходные файлы компонентов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284Конфигурация: pubspec .yaml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286Класс GameObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287Расширение GameObject: класс Enemy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291Расширение GameObject: класс Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293Место, где все начинается: main .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296Основной игровой цикл и основная игровая логика . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301

Начнем . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301Первичная инициализация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302Коротко об анимациях во Flutter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303Сброс состояния игры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305Основной игровой цикл . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307Проверка на наличие столкновений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310

Page 5: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

11

Размещение объекта в случайной точке . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312Передача энергии . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312

Все под контролем: InputController .dart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315Что дальше? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317

УКАЗАТЕЛЬ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .318

Page 6: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

12

Об авторе

Фрэнк Заметти – автор ряда популярных технических книг, был програм-мистомоколо40лет,25изкоторыхзанималсяэтимпрофессионально,надожеемубылочто-токушать.Втевременанаеговизиткезначилосьархитектор,хотяонпродолжалписатьтупойкодикаждыйденькрутилсякакмог.Фрэнк–первоклассныйгик:еслионнезаставляетсвойкомпьютервыполнятьприка-зы(скореевсего,дьявольские),тозанятпросмотром,чтениемилинаписаниемнаучнойфантастики,моделированиемрельсотрона,катушкиТеслыилилю-бойдругойштуковины,способнойприкончитьеговлюбоймомент;онлюбитбезпричиныцитировать «Вавилон 5», «Властелин колец», «Хроники Риддика» или«Настоящих гениев»,атакжеигратьвкомпьютерныеигры.ЕщеФрэнк–рок-музыкант (клавишник) и заядлый любитель пиццы и других углеводов.Унегоестьжена,собакаинесколькодетей.Еслиподвестиитогегокрутости,тоонтот,ктовсегдаготоввоскликнуть«Стобоймоймеч!»(нуда,обычногикицитируют«Властелин колец»безочевиднойпричины).

Page 7: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

13

О техническом рецензенте (обозревателе)

ГерманванРосмаленработаетразработчикомиархитекторомпрограммногообеспечениядляDeNederlandscheBankNV,центрального банкавНидерландах.Заегоплечамиболее30летопытаразработкиприложенийнараз-ныхязыкахпрограммирования.Германбылвовлеченвсозданиеприложенийдлямейн-фреймов, десктопов, серверов, веб-браузе-ровисмартфонов.Последние4годаонзани-мается в основномразработкойна .NET/C#иAngularпосле15летработысJava.

Германживет в маленьком городке Пей-наккервНидерландахсосвоейженойЛизбети детьми Барбарой, Леони и Рамоном. На-равнесразработкойсофтавсвободноевре-мя Фрэнк тренирует женскую футбольнуюкомандунапротяжениипоследних10лет.

И конечно же, он болеет за Фейеноорд(футбольныйклубизгородаРоттердамвНи-дерландах,которыйсчитаетсяоднимизве-дущихклубовстраны)!

Page 8: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

14

О переводе

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

Надпереводомкниги«Flutterнапрактике»работали:

Артем Тищенко, переводчик–руководительнаправленияMobileвком-панииBinwell,специалиствразработкенативных(iOSSwift/ObjectiveC),атак-жекроссплатформенных(XamarinиFlutter)мобильныхприложений.МенторBinwell University, соавтор ряда популярных статей для Microsoft DeveloperBlogsиХабрахабры.

Вячеслав Черников, редактор перевода–руководительразработкивком-панииBinwell,руководительBinwellUniversity.РаботаетвсфереMobileираз-работкиПОс2005года.СоздавалприложенияиигрыдляiOS,Android,Symbian,WindowsMobile,Meego,LinuxиWindowsUWP.Имеетбогатыйопытразработкинативных(iOSSwift/ObjectiveC)икроссплатформенных(Xamarin,Qt,PhoneGap/HTML5,Unity)мобильныхприложений.Авторкниги«РазработкамобильныхприложенийнаC#дляiOSиAndroid»(ДМКПресс,2020),атакжепопулярныхстатейдляХакера,Хабрахабры,MicrosoftDeveloperBlogs,спикер,преподава-тельинемного[безумный]ученый.

ТакжевыражаемблагодарностьАлександру РыжковуиСергею Селютину запомощьскорректировками.

Page 9: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

15

Благодарности

Есливыникогданезанималисьнаписаниемкниги,тояоткроювамсекрет:написаниесамойкниги–этолишьмалаячастьбольшойработынадней.Ино-гда,мнекажется,наименьшаячасть!

Поэтомуяхочупоблагодаритьвсех,ктоусердноработалипомогалсэтимпроектом(неважно,личноилисредактурой),включаяНэнсиЧен,ЛуисаКор-ригана,ДжеймсаМаркхэма,ГерманаванРосмалена,ВэлмодаСпараиДанишаКумара.Есливашегоименинетвсписке,хотяонодолжноздесьбыть,яприно-шусвоиискренниеизвиненияиблагодарювас.

Такжея хотелбыпоблагодаритьЛарсаБакаиКаспераЛанга за созданиеDart, довольно элегантногои оченьприятного в использовании языкапро-граммирования,лежащеговосновеFlutter.Говорюкакчеловек,которыйсо-здалсвойсобственныйязыкинаборинструментовдлянегомноголетназад,яочень-оченьценюто,чтовысделали,ребята.Честьвамислава!

РаботанадкнигойпоFlutterтребуетотменяблагодарностипочтивсейко-мандеразработчиковэтогофреймворка.Я занимаюсьмобильнойразработ-койоколо20лет(посмотритенаetherient.com,страницуProducts,аконкрет-ноEliminator–игра,которуюявыпустилв2001годудляплатформыPocketPC;яверю,чтоэтобыломоепервоемобильноеприложение,покрайнеймереперваяудачнаяпопытка),итогда,насколькоямогусудить,яиспользовалдо-статочномногоутилит,фреймворковибиблиотек.Учитываявесьэтотопыт,ямогусуверенностьюсказать,чтоFlutterдажеспервойверсиибылнаголовувышевсех.

Этопоразительно, сколькокомандаFlutter смогла сделать затакойотно-сительнокороткийпериодвремени,ибезихтяжелойработыябы,очевидно,ненаписалэтукнигу!ЯснетерпениемждувозможностивсебольшеибольшеиспользоватьFlutter,атакжемнеоченьинтересно,чтобудетсFlutterдальше!

Page 10: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

16

Введение

Создание кроссплатформенных приложений, которые выглядят и работаюткакнативные,–сложнаязадачадажепослемногихлетработынадеерешени-ем.Выможетеписатьотдельныепрограммыдлякаждойплатформыипытать-сясделатьихдизайнмаксимальнопохожим.Нофактическиэтозначитнапи-сатьодноприложениенесколькораз.Заказчики,какправило,неготовызата-коеплатить!

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

Язанимаюсьэтимужевтороедесятилетие(серьезно!),поэтомуявиделта-коемногораз.Иеслиязамечунагоризонтеобразединорога,тобудусомне-ватьсядоконца.Однакоесли,подойдяпоближе,окажется,чтоединорогдей-ствительнореален?

Итак,япредставляювамединорога,которыйнасамомделесуществует,–Flutter!

БлагодаряталантливыминженерамизGoogleFlutter–этоплатформа,по-зволяющаяписать(болееилименее)кроссплатформенныйкод,которыйоди-наковоработаетнаAndroidиiOS,приэтомобеспечиваяпроизводительность,идентичную нативным приложениям. Flutter, созданный с использованиемсовременныхинструментовиметодовразработки,открываетпрограммистаммирмобильнойразработки,вкотором,даженепобоюсьсказать,веселорабо-тать!

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

Вытакжеузнаетето,каксоздаватьсерверныеприложениянаNode.jsиWebSockets. Эти бонусы являются полезным дополнением к описанию самогофреймворкаFlutterиязыкаDart.

Крометого,высможетесоздатьдополнительноетретьеприложение,кото-роеразительноотличаетсяотпервыхдвух,–игру!Да,мывместесоздадимигрунаFlutter,чтобырассмотретьтакиевозможности,которыередковстречают-сявнастоящихприложениях,нодаютвамвзглянутьнафреймворксразныхсторониполучитьмаксимумопыта.Этаиграможетбытьнесовсем«практич-ной»,ноигрывсегдаувлекательны,анемноговесельяникомунеповредит!

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

Page 11: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

17

ВВЕДЕНИЕ

Есливыбыликомпьютернымэнтузиастомв80-хгодах,тонавернякапом-ните,каковоэтобыло–набиватьнасвоемкомпьютеремашинныйкодизжур-нальнойстатьив20страницмелкимшрифтом,чтобысыгратьвигруилиза-пуститьприложениедлясверкивашихдоходовирасходов(да,мыдействи-тельноэтоделали–былидажерадиостанции,транслировавшиеисходники,которыезатемкомпилировалисьвготовоеприложениеспомощьюспециаль-нойутилиты,подобнотомукаксейчаскодируетсязвукдляпередачипотеле-фоннойлинии).

Итак,преждечемначать,япредлагаювамзайтинавеб-сайтApress,найтиэтукнигуискачатьсебеисходныекодыпримеров.Этопозволитобойтисьбезстиранияпальцеввкровь,перепечатываялистингиизкниги!

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

Итак,приготовьтеськприятнойиинформативнойпоездкевмирFlutter!Янадеюсь,чтовампонравитсяэтакнигаивымногомунаучитесь.Этомоя

главнаяцель!Такчтоперекусите,сядьтевкреслепоудобнее,подготовьтено-утбукиприступайте.Васждутприключения!(Да,япрекраснопонимаю,какбанальноэтозвучит.)

Исходные коды примеров вы можете найти в репозитории на GitHub:https://github.com/Apress/practical-flutter.

Page 12: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

18

ГЛАВА 1 .

FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Поехали!Если вы спросите десять разных разработчиков мобильных приложений,

какониихразрабатываютдляAndroidиiOS,то,скореевсего,получитедесятьразныхответов.Ноэтоненадолго,благодарядебютантунаэтойсцене–Flutter.

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

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

Медитации над безднойРазработкасофта–этонепростаязадача!

Янехочуутомлятьвасисторией,нофактвтом,чтояначал,такилииначе,программироватьс7лет,аэтоозначает,чтоязанимаюсьэтимпочти40лет(около25изнихпрофессионально).Ямногоповидалимногосделал,ноглав-ное,чтояпонял:разработкасофта–этонепростаязадача.Конечно,некото-рыеотдельныезадачиипроектымогутбытьпростыми,новцеломэтодо-вольносложнаяработа,котороймызанимаемся!

Иэтомыещенеговоримомобильнойразработке,котораякудасложнее!Яначалразработкумобильныхприложенийпримернодвадесятилетияна-

зад,ещевовременаWindowsCE/PocketPCиPalmPilot(былиидругиеплатфор-мы,ноименноэтидвебылиединственныминастоящимиигрокаминарынке).Тогдавсебылонетакужиплохо,несмотрянаограниченныйнаборустройствивозможностейинструментовразработки,которымимырасполагали.Безус-ловно,использованиеэтихинструментовбылонетакимприятным,каксегод-ня,нобылвсегоодинспособразработкиприложенийдляPocketPC,одинспо-собразработкиприложенийдляPalmOS.Звучитнеочень,ноотсутствиевы-бораприводиткотсутствиюпутаницы,чтоявляетсяоднойизсамыхбольшихтрудностейвобластиразработкисофтанасегодняшнийдень.

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

Стехпориндустриямобильныхустройствиприложенийпретерпеланема-лоэволюционныхизменений,подъемовипадений.Долгоевремяунасбыломногоплатформдляподдержки:Android, iOS,webOS,Tizen,WindowsMobileинесколькодругих,которыеядаженепомню.Всеэтовремяпереносприло-

Page 13: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

19

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

жениймеждуплатформамибылнормой,посколькунебылохорошегокросс-платформенногоподхода,покрайнеймеребезсущественныхкомпромиссов.Да,современемсталопроще,потомучтоулучшилсяинструментарийдляна-тивнойразработки.AppleвыпустиласвойSDKдляiOSв2008году,аGoogleвы-пустилсвойAndroidSDKгодспустя–в2009-м.Намприходилосьразрабаты-ватьприложениядлякаждойплатформы,посколькуразработкаiOSосновананаязыкеObjective-C(сегоднячащенаязыкеSwift),втовремякакразработкаAndroidоснованапреимущественнонаязыкеJava(теперьчащенаKotlin).

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

Наша прогрессивная эпоха интернета предлагает создавать приложенияспомощьютехнологий,лежащихвегооснове,икакрезультатполучитьпри-ложение,котороевыглядитиработаетпримерноодинаковонаобеихплатфор-мах(теоретическиинадругихтоже).Этосопровождаетсякомпромиссами,ко-торыесовременемминимизируются,новсеещесуществуют.Такиевещи,какпроизводительностьипрямойдоступквозможностям«железа»,всеещеслож-носовместитьсвеб-технологиями.

Однако,помимовеб-технологий,впоследниенескольколетмынаблюда-лирождениеидругихкроссплатформенныхинструментов,которыепозволя-ютнамнаписатьприложениеодинразиработатьснимпримерноодинакововразныхоперационныхсистемах.Популярныеварианты–CoronaSDK(впер-вуюочередьдляигр,нонеобязательно),Xamarin,PhoneGap(простовеб-тех-нологии, умно завернутые в собственный компонент WebView), TitaniumиSenchaTouch(опятьже,наосновевеб-технологий,носхорошимслоемаб-стракциинадним),может,ещенесколько.Такчтосейчаснамдоступномно-жестворазличныхвариантов,каждыйсосвоимиплюсамииминусами.

Атеперьвнимание!Нааренувыходитновыйконкурент,жаждущийубитьостальныхипоказатьединственныйверныйпутьнаписаниякроссплатфор-менныхмобильныхприложений:Flutter.

Да,этонемногоглупоеназвание...нознаете,мыможемзакрытьнаэтогла-за,потомучтопреимуществунеговышекрыши!

Что за (глупое) название?Flutter–этопродуктGoogle–ну,вызнаете,корпорации,котораяоснователь-ноконтролируетинтернет,хорошоэтоилиплохо(вслучаесFlutterядумаю,чтохорошо).ИзначальноэтотфреймворкродилсяподименемSkyв2015годунасаммитеразработчиковDart(незабудьтеэтослово,Dart,мыкнемускоровернемся).СначалаонработалтольконаоперационнойсистемеAndroidотса-могоGoogle,новскоребылпортированинаiOS,такчтосегодняонподдержи-ваетдвеведущиемобильныеоперационныесистемы.

Page 14: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

20

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ПервыеверсииFlutterбыливыпущенысразупослеегоанонса, акульми-нациейсталвыпускстабильнойверсии«Flutter1.0»4декабря2018года.По-слеэтогоFlutterбылготовкпрайм-тайму,ипришловремядляразработчиковзапрыгиватьнаборт!ПопулярностьFlutterможнобылобыохарактеризоватькакметеорическую,инаэтоестьвескиепричины.

Однаизнихзаключаетсявследующем:первоначальнозаявленнаяцельFlut-terили,покрайнеймере,однаизосновных,заключаласьвотрисовкепользова-тельскогоинтерфейсасоскоростью120кадроввсекунду.Googleосознавал,чтоотзывчивыйинтерфейсприведетпользователейввосторг,поэтомуэтафунк-циональностьилеглавосновуFlutter.Этоблагороднаяцель,которойдостига-ютлишьнемногиекроссплатформенныефреймворки(даженативныеинстру-менты–итечастоиспытываюттрудностисоскоростьюотрисовкисложногоинтерфейса).

Flutterтакжепредоставляет свои готовыекомпонентыпользовательскогоинтерфейса–вотличие,например,отXamarinиReactNative,оннеиспользуетнативныеконтролы.Другимисловами,когдавыхотите,чтобыFlutterотобра-зилкнопку,онрисуетеесам,анепроситобэтомоперационнуюсистему,какделаютдругиефреймворки.ИменноэтоиотличаетFlutterотостальныхипо-зволяетприложениямбытьодинаковыминаразныхплатформах.Важното,чтоновыекомпонентыпользовательскогоинтерфейса,иливиджеты(этосло-вотожезапомните,потомучто,какиDart,онотожескоровстретится),могутбытьдобавленывоFlutterбыстроилегко,небеспокоясьотом,поддерживаетлиихсамаоперационнаясистема.

ЭтотакжепозволяетFlutterпредоставлятьспецифическиенаборывидже-товвстилистикахMaterialиCupertino.ПервыйреализуетMaterialDesignотсамойGoogle–стильAndroidпоумолчанию.ПоследнийреализуетстильiOSотApple.

Flutterможноразделитьначетыреосновныечасти,включаяDart.Ясобира-юсьоставитьэтодоследующегораздела,такчтодавайтеперейдемковторо-мукомпоненту–основномудвижкуFlutter.ЭтотдвижоквосновномнаписаннаC++ииспользуетбиблиотекуSkia,такчтопроизводительностьотрисовкисравнимаснативной.Skia–этонебольшаяграфическаябиблиотекасоткры-тымисходнымкодом,котораятакженаписананаC++иимееточеньвысокуюпроизводительностьнавсехподдерживаемыхплатформах.

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

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

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

Page 15: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

21

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ТеперьдавайтеболеедетальноразберемDartивиджеты,окоторыхговори-лиранее.

Dart: Язык богов?КогдаGoogleначалработатьнадFlutter,импредстоялоответитьнаглавныйвопрос:какойязыкпрограммированиявыбрать?Можетбыть,языквеб-раз-работки,такойкакJavaScript?ИлижеJava,языкAndroid?ИлирадиподдержкиiOSвыбратьSwift(вконцеконцов,Swiftявляетсяязыкомсоткрытымисход-нымкодом)?Возможно,что-товродеGoилиRubyбылобыхорошимвариан-том.Какнасчет«старойшколы»,C/C++?Аможет,попробоватьC#отMicrosoft(унеготожеоткрытыйисходныйкод)?

Яуверен,чтобыломноговариантов,новконцеконцовGoogleрешил(небезпричины!)использоватьязык,которыйонисоздалинескольколетназад:Dart.

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

import "dart:math" as math;

class Point { finalnumx,y; Point(this.x,this.y); Point.origin():x=0,y=0; numdistanceTo(Pointother){ vardx=x–other.x; vardy=y–other.y; returnmath.sqrt(dx*dx+dy*dy); }

Pointoperator+(Pointother)=>Point(x+other.x,y+other.y);}

voidmain(){varp1=Point(10,10);varp2=Point.origin();vardistance=p1.distanceTo(p2);print(distance);

}

Необязательносразудетальнопониматьвсё,чтовыздесьвидите.ТемнеменееесливыработалираньшеслюбымС-подобнымязыком,напримерJavaили JavaScript,тоготовпоспорить,чтовыбезпроблемвовсемразберетесь.ВэтомизаключаетсяглавноепреимуществоDart:большинствосовременныхразработчиковсмогутнаписатьипонятьподобныйкоддовольнолегко.

Page 16: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

22

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ПРИМЕЧАНИЕ. Интересно, что мы называем языки C-подобными, но сам C – потомок гораздо более старого языка ALGOL . Я думаю, что ALGOL никогда не получит заслуженного уважения, так что этой ре-маркой я выражаю всю любовь к нему!

Невдаваясьвовсемельчайшиеподробности(дляэтогопредназначенасле-дующаяглава),ядумаю,чтодаженебольшойсправкипоDartбудетдостаточ-но.GoogleсоздалDartещев2011году,иизначальноонбылпредставленнаконференции GOTO в Орхусе, Дания. Первый релиз 1.0 состоялся в ноябре2013года,примернозадвагодадовыпускаFlutter.ЗаDartстоитблагодаритьЛарса Бака (который разработал ещё и JavaScript-движокV8, используемыйвChromeиNode.js)иКаспераЛунда.

Dart–этолаконичныйязык,которыйбыстронабираетобороты,восновномблагодаряFlutter.Посколькуонсчитаетсяязыкомобщегоназначения,егоши-рокоиспользуютдлясозданиявеб-приложений,серверногокодаиприложе-нийIoT(InternetofThings,«интернетвещей»).Покаяписалэтуглаву,вышелопросотом,какиеязыкипрограммированиявызываютнаибольшийинтересразработчиковв2019году,опубликованныйJAXenter:https://jaxenter.com/poll-results-dart-word-2019-154779.html. В результате два языка заметноопередилиостальные:DartиPython,Dartвырвалсявперед.Dartиспыталнаи-большийроств2018году.ИхотяFlutter–почтинавернякаодинизсамыхпо-пулярныхвариантовегоиспользования,но,несмотрянаэто,Dartразвивает-сявовсехнаправлениях.Такчтобудьтеуверены,Dartнеобделенвниманием.

ТакчтожетакоеDart?Предыдущийпримеркодадемонстрируетглавныеключевыемоменты,окоторыхяхотелсказать:

• Dartполностьюобъектно-ориентирован;

• инфраструктураязыкавключаетвсебясборщикмусора,поэтомунетне-обходимостиследитьзапамятью;

• егосинтаксисоснованнаC,которыйподойдетбольшинствуразработчи-ков(темнеменее,какиулюбогодругогоязыкаспохожимсинтаксисом,унегоестьрядособенностей,которыепоначалумогутсбитьвасстолку);

• он поддерживает общие языковые конструкции, такие как интерфей-сы,наследование,абстрактныеклассы,шаблонныеклассы(generics,или«дженерики»)истатическуютипизацию;

• Dartвключаетпроверкусоответствиятипов.Этопозволяетиспользоватьалгоритмдляконтроляправильностивашегокода;

• онподдерживаетмногопоточность,такчтоодновременноможетиспол-нятьсянесколькоотдельныхпроцессов,обеспечиваявысокуюпроизво-дительность;

• Dartможеткомпилироватьсявнативныйкоддляповышенияпроизводи-тельности.ОннетолькокомпилируетсявкоддляпроцессоровARMиx86врежимеAheadOfTime(присборкеприложения),ноиможеттранслиро-

Page 17: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

23

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ватьсявJavaScript,атакжеподдерживаетдинамическуюкомпиляциювовремяисполнения(JustInTime);

• Dartпозволяетиспользоватьбольшойнаборрепозиториевсготовымиби-блиотеками,которыеобеспечиваютдополнительнуюфункциональностьдлявсего,чтоможетпонадобитьсяразработчикам;

• поддержкапопулярныхсредразработки,включаяVisualStudioCodeиIntelliJIDEA;

• ядроDartподдерживаетсоздание«слепков»(snapshots),которыепозво-ляютупаковатьвесьисполняемыйкод(нетольковашкод,ноибиблиоте-ки)вединыйдвоичныйфайл,чтоускоряетзапускприложения.

DartтакжезарегистрированвкачествемеждународногостандартаECMA-408,аегоактуальнуюспецификациювсегдаможнополучитьнасайтеwww.dartlang.org/guides/language/spec.

Какяужеотмечалранее,всявтораяглавабудетпосвященаDart,апокамыперейдемкследующейважнойтеме.

Виджеты окружают!Давайтевернемсякразговоруоглавномгостенашегошоу,Flutter,иконцеп-ции,котораялежитвегооснове,–виджетах.

Flutter–этоиестьвиджет.Когдая говорю,чтоон и есть виджет,яимеюввиду...ну...яимеюввиду,чтопочтивсевнемявляетсявиджетом(гораздосложнеенайтивоFlutterто,чтовиджетомне является!).

Чтожетакоевиджет,спроситевы?Эточастивашегопользовательскогоин-терфейса(хотяиневсевиджетыявноотображаютсянаэкране).Виджеттакжепредставляетсобойфрагменткода,например:

Text("Hello!")

…иэтотакжевиджет...

RaisedButton( onPress:function(){ //Сделайчто-нибудь. }, child:Text("Clickme!"))

...иэтотожевиджет...

ListView.builder( itemCount:cars.length, itemBuilder:(inContext,inNum){ returnnewCarDescriptionCard(card[inNum]); })

Page 18: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

24

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

...инаконец,этовиджет:

Center( child:Container( child : Row( Text("Child1"), Text("Child2"), RaisedButton( onPress:function(){ //Dosomething. }, child:Text("Clickme") ) ) ))

Последнийпримеринтересентем,чтонасамомделеэтоиерархиявидже-тов:виджетCenter,авнемвиджетContainer,содержащийвиджетRow,кото-рый,всвоюочередь,содержитдочерниевиджетыTextикнопкуRaisedButton.

Неважно,чтоэтозавиджеты(хотяназванияихотличнохарактеризуют),главное, что всяиерархиявиджетов, которуювывидите, сама по себетакжесчитаетсявиджетомFlutter.

Да,воFlutterповсюдувиджеты!Виджетыокружают!Flutter–этоОпра[По-пулярнаяведущаяТВ-шоувСША.–Прим. перев.]вмирефреймворковпользо-вательскогоинтерфейса:вамнуженвиджет–выполучаетевиджет!Да,выпо-лучаетевиджет!ВыВСЕполучаетевииииииджеты!

Какясказалранее,воFlutterпрактическивсе–этовиджет.Естьочевидныевещи,окоторыхлюдидумают,употребляяслововиджетвконтекстепользо-вательскогоинтерфейса:кнопки,списки,изображения,полятекстовыхформивсетакоепрочее.Этовсевиджеты.НовоFlutter-то,чтовывиджетаминесчи-таете,этовсеещеони.Например,рамкавокругизображения,состояниеполятекстовойформы,текст,отображаемыйнаэкране,дажетема,которуюисполь-зуетприложение.

Врезультатемывидим,чтокодвоFlutter–этогигантскаяиерархиявид-жетов(иэтаиерархияимеетконкретноеимявоFlutter:WidgetsTree,«деревовиджетов»). Видите ли, большинство виджетов являются контейнерами, этоозначает,чтоонимогутиметьдочерниеэлементы.Некоторыевиджетымогутиметьтолькоодинтакойэлемент,втовремякакдругиемогутиметьмного.Итогдаукаждогоизнихможетбытьодинилинесколькодочернихэлементов,итакдалее,итакдалее!

ВсевиджетыявляютсяклассамиDart,иунихестьобязательноетребование:предоставитьметодbuild().Этотметоддолженвозвращать...подождите,по-дождите...другие виджеты!Естьоченьмалоисключенийизэтого,напримернизкоуровневыевиджеты,такиекаквиджетText,которыйвозвращаетприми-

Page 19: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

25

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

тивныйтип(внашемслучае–String),нобольшинствовозвращаютодинилинескольковиджетов.Помимоэтоготребования,виджет–этостарыйдобрыйклассDart,которыйнеотличаетсяотклассавлюбомдругомобъектно-ориен-тированномязыке(заисключениемсинтаксиса).

ВиджетвоFlutterрасширяет(extends)одинизстандартныхклассов,кото-рыеонжеипредоставляет, что характернодляобъектно-ориентированнойпарадигмы.Расширенныйкласс (extendedclass)определяет, скакимвидже-томмыимеемделонафундаментальномуровне.Естьдвасамыхбазовыхклас-са,которыевыбудетеиспользовать,вероятно,99%времени:StatelessWidget иStatefulWidget.

Виджет,унаследованныйотStatelessWidget,неизменяетсяпослеотображе-нияиназываетсявиджетомбезсостояния,потомучтооннеимеетсостояния(логично).Такиевиджеты,какIcon(отображаетнебольшиеизображения)иText (отображаетстрокитекста),тоженазываютвиджетомбезсостояния.Примеромподобногоклассаможетбытьследующее:

classMyTextWidgetextendsStatelessWidget{ Widgetbuild(inContext){ returnnewText("Hello!"); }}

Да,здесьнетничегоособенного!В отличие от StatelessWidget, наследники базового класса StatefulWidget

изменяются, когда пользователь взаимодействует с ним. CheckBox, Slider,TextField–этовсеизвестныепримерывиджетовссостоянием(и,кстати,ког-давывидите,чтоонинаписанысбольшойбуквы,тоэтоозначает,чтояимеюввидуфактическиеименаклассовFlutter,анеобщиетермины).Когдавыкоди-руететакойвиджет,вамнужносоздатьдвакласса:самклассвиджетассостоя-нием(StatefulWidget)икласссостояния(State),связанныйсним.ВотпримервиджетаStatefulWidgetисвязанногоснимклассаState:

classLikesWidgetextendsStatefulWidget{ @override LikesWidgetStatecreateState()=>LikesWidgetState();}

classLikesWidgetStateextendsState<LikesWidget>{ intlikeCount=0;

voidlike(){ setState((){ likeCount+=1; }); }

@override

Page 20: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

26

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ Widgetbuild(BuildContextinContext){ return Row( children:[ RaisedButton( onPressed:like, child:Text(‘$likeCount’) ) ] ); }}

Опятьже,янежду,чтовыполностьюпойметеэтоткод,таккакрасширятьзнанияпоDartмыначнемпозже.Ноявсёравносчитаю,чтовыприблизи-тельнопонимаете,чтоздесьпроисходит.Покрайнеймере,то,каккодвиджетаиегообъектсостояниявзаимодействуютисвязаны.Может,этонетакужоче-видно,нонебеспокойтесь,этоненадолго!

Возвращаяськвиджетамбезсостояния,следуетотметить,чтотермин«вид-жетбезсостояния»несовсемточен,потомучто,будучиклассомDart,которыйимеетсвойстваиинкапсулированныеданные,виджетыбезсостояниявне-которомсмыслеимеютсостояние.ОсновноеразличиемеждуStatelessWidgetи StatefulWidget заключается в том, что виджет без состояния (stateless) неумеетавтоматическиперерисовыватьсяприизмененииего«состояния»,тог-дакаквиджетссостояниемможет.Когдавиджетссостояниемизменяется,не-зависимооттого,чтовызываетизменение,возникаютопределенныесобытияжизненногоцикла.Когдасостояниевиджетаизменяется,топроисходитвызовопределенныхметодов,ионперерисовывается (еслинеобходимо,тоFlutterделаетэтоавтоматически)

Представьте:обатипавиджетовмогутиметьсостояние,ноFlutterраспозна-етиуправляеттолькоstateful-виджетом.Такимобразом,толькоStatefulWidgetможетбытьавтоматическиперерисованвответнавнешнеесобытие,иэтокон-тролируетсясамимFlutter,авамненужнопрописыватькодвручную.

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

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

Page 21: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

27

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

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

Покаэтовсе,чтонужнознатьовиджетах.Мыизучимкаталогвиджетовболееподробноначинаясглавы3,и,конечно,мырассмотримиспользованиекаждо-гоизнихвглаве4,когдабудемделатьприложениясними.Вконцеконцов,выполучитехорошиезнанияонаиболеераспространенныхвиджетахFlutter,атакжедругие,неменееполезныебазовыенавыкииспользованияисозданиявиджетоввцелом.

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

ДавайтеужеобсудимвсеплюсыиминусыFlutter,атакжесравнимегоскон-курентами.

• За:горячаяперезагрузка(hotreload)–кнейявернусьпослетого,какмыизучимнастройкуокруженияивзглянемнапервыйпримерприложения–высамиубедитесь,чтоэтобольшоепреимуществоFlutter.ReactNativeтак-же включает возможность горячей перезагрузки, особенно если вы ис-пользуетестороннийкомпонентExpo.ОднаковоFlutterэтафункциональ-ностьреализованаболеекачественноистабильно.Немногиефреймворки,даженативные,могутпохвастатьсяподобнымивозможностями.

• Против: только для мобильных устройств. На момент написания этойкнигиможнобылоиспользоватьFlutterтолькодляразработкимобиль-ныхприложенийiOSиAndroid.ЕсливыполюбитеFlutter,тобудетеразо-чарованытем,чтонесможетеиспользоватьегодляразработкивсехва-шихприложений.Темнеменееобратитевнимание,чтояначалсослов«намоментнаписания».Этопотому,чтосвысокойстепеньювероятностиFlutterтакжебудетдоработандляподдержкиприложенийдлявеб-брау-зеров,Windows,macOS,Linuxидругихплатформ.[Ида!Flutterпортиро-валинавеб-браузерыидесктопныеплатформы,хотяпроцессэтотещетольконачался.–Прим. перев.]

Page 22: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

28

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

• За:да,ондействительнокроссплатформенный–вашиприложенияFlutterбудуткорректноработатьнаiOSиAndroid(ивконечномитогепреемни-кеAndroid–Fuchsia).Flutterпоставляетдванаборавиджетовизкоробки,одиндля iOSиодиндляAndroid,поэтомувашиприложениямогуткаквыглядетьодинаковонаобеихплатформах,такиучитыватьстилистикуцелевойоперационнойсистемы.

• Против: веб-разработчики, не привыкшие видеть описание логикипо-веденияиразметкипользовательскогоинтерфейсаводномклассе,какправило,оченьэмоциональнореагируютнапримерыFlutter.Длясравне-ния,ReactNative,укотороготакжеводномклассеописываетсяилогикаиразметка,первоевремястрадалотподобныхжалоб,нопотомразработ-чикипривыкли.

• За:Dart–простойимощный,объектно-ориентированныйистроготи-пизированный,чтопозволяетразработчикамбытьоченьпродуктивны-ми,быстрымииделатьменьшеошибок.Кактольковыпройдететерни-стыйначальныйпутьобучения,вампонравитсяDart,особенновсравне-ниисJavaScript,Objective-CилиJava.

• Против:Google–япричисляюэтокнедостаткам,ивыопределенномо-жетесомнойнесогласиться(раньшеячастоспорилобэтомсамссобой).НекоторыелюдичувствуютсебянекомфортнооттакогоконтроляGoogleнадинтернетом,дажееслиGoogleэтимактивнонепользуется.Когдавыдоминируете,то,какправило,многоеконтролируете.Темнеменеенеко-торыелюдиопасаются,чтоGoogleнаращиваетоборотыинаещеодномнаправлении–длянихэтоможетбытьужеслишком.Другие,конечно,посмотрятнаэтоискажут,какздорово,чтогигантподдерживаеттакуюзамечательную технологию. Так что этот «недостаток» можно назватьспорным.Ивыбратьсторонуможететольковы.

• За:виджеты–Flutterпредоставляетразработчикамбогатыйнаборвидже-тов,иэтогоможетбытьвполнедостаточнодляпостроениялюбогопри-ложения.Вытакжеможетесоздаватьисвойсобственныйвиджет(наса-момделевывсегдабудететакделать,неважно,накакомуровне),идажеиспользоватьмногиесторонниевиджеты,дабырасширитьвозможностиприложения.Этивиджетытакжепростывиспользовании,каките,чтонампредлагаетсамFlutter.

• Против: дерево виджетов (widgets tree) может стать недостатком, ведьиногда вы будете сталкиваться с очень глубоко вложенной иерархией,иразобратьсясоструктуройкодастанетнетак-топросто.Сразвитиеминтернетамыкэтомуужепривыкли,потомучтоHTMLсампосебеявля-етсядревовидным,однакопосколькупрактическивсевоFlutterявляетсявиджетами,иерархияиногдаможетбытьдажеглубжеHTML,астилькодаDart выглядит сложнее. Конечно, естьметоды, позволяющие это упро-стить.Ноонихярасскажупозженапримерахреальногокода,ида,это

Page 23: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

29

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

всеещенедостаток,потомучтовыдолжныосознаватьегоиуметьрабо-татьснимсамостоятельно.НиFlutter,ниDartнепредложатвамподска-зокврешении.

• За:инструменты–каквыувидитевследующемразделе,настроитьсре-дуразработкидляFlutterоченьлегко.Темнеменеевыможетевыйтизапределыэтойбазовойсредыииспользоватьмногиеужепривычныеваминструменты.

• Против:реактивноепрограммированиеиуправлениесостоянием–Flut-terобычносчитаетсяреактивным(reactive).Методbuild(),которыйвывиделиранее,принимаетвкачествеаргументатекущеесостояние,ато,чтоонвозвращает,–этовизуальноепредставлениеэтоговиджета,наос-новеобновленногосостояния.Когдаобновляетсясостояние,виджет«ре-агирует»наэтоиобновляетсебяспомощьюповторноговызоваметодаbuild().Всёэто–стандартныймеханизмFlutterитиповойжизненныйциклвиджета.Сравнитеэтос«нереактивными»подходами,когдавысоз-даетевиджет,азатемсамостоятельновызываетенужныеметодыдляегомодификацииилиобновления.Вцеломреактивнаяпарадигмадовольноудобна,хотядляFlutterонаможетбытьинедостатком,потомучтоиногдаэтоусложняетпростыевещи(высамиувидитеподобныепроблемывпо-следующихглавах,атакженаучитесьснимисправляться).Сэтимсвяза-наисложностьуправлениясостояниями,котораяявляетсянедостаткомFlutterвтомсмысле,чтонетканоническиправильногоинеправильно-госпособаэтоделать.Существуетмножествоподходов,иукаждогоестьсвоиплюсыиминусы,авамнужнобудетрешить,чтолучшесоответству-етвашимпотребностям(ида,ябудупредлагатьто,чтосчитаюхорошимподходом).Googleработаетнадтакимканоничнымподходомпрямосей-час,нопокаоннеготов,ябудурассматриватьотсутствиеопределенногопутикакнедостаток(хотянекоторыесчитаютгибкостьпреимуществом!).

• За: специфические для платформы виджеты – поскольку интерфейсыFlutterпишутсяспомощьюкода,увасможетбытьоднакодоваябаза,ко-тораяподдерживаеткакiOS,такиAndroid,нодажевнейестьразличия,которыевамнужноучитывать.Например,вывсегдаможетеузнатьвкодезначенияPlatform.isAndroidиPlatform.isIOS,чтобыопределить,нака-комустройствеработаетвашеприложение,азатемдобавитьусловиедлясозданияразныхвиджетовдляразныхплатформ.Возможно,вамнуженRaisedButtonнаAndroidиButtonнаiOS.

• Против:размерприложения–приложенияFlutter,какправило,немно-гобольшесвоихнативныханалогов,потомучтоонивключаютосновнойдвижокFlutter, библиотекиидругиересурсыфреймворка.Размерпри-ложенияэлементарного«Hello,world!»наFlutterможетпревышать7МБ.Поэтомуесливамрешительноваженразмерприложения,тоFlutterмо-жетстатьнелучшимвыбором.

Page 24: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

30

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Надеюсь,чтокэтомумоментууваспоявилосьпониманиесильныхислабыхсторонFlutter,поэтомупредлагаюперейтикпрактике.

Хватит болтать, начинаем практику с Flutter!Преждечеммыдоберемсядокода,намследуетустановитьFlutterинекото-рыеинструменты,которыемогутпонадобиться.Надеюсь,выпонимаете,чтонетакужпростоначатьписатькоднаFlutter,неустановивего!

Ксчастью,настроитьрабочееокружениедовольнолегко.

Flutter SDKПервыйшаг,которыйвыдолжнысделать,–этозагрузка,установкаинастрой-каFlutterSDK.Этооченьважно!Второйшаг,которыйтехническинеобязате-лен,нонеобходимдляцелейэтойкниги,–этозагрузка,установкаинастройкаAndroidStudio,включаяAndroidSDKиэмулятор.

Во-первых,зайдитенаhttps://flutter.ioдлязагрузкиустановочныхпа-кетовиполучениядокументацииFlutter.НажмитекнопкуGet Startedвверх-нейчасти.НайдитеInstallивыберитесвоюоперационнуюсистему(Windows,MacOSилиLinux).

Обратите внимание, что мне совсем не стыдно признать, что я в первую очередь пользователь Win-dows . Это то, в чем я разбираюсь и что предпочитаю! Так что эта книга будет ориентирована на Windows, и если вы используете другую ОС, то вы в какой-то степени будете сами по себе . С учетом вышесказан-ного я буду обращать ваше внимание на особенности инструментов для разных ОС, если будут иметь-ся существенные различия . На самом деле их не должно быть вне зависимости от того, используете вы Windows или нет . При этом Flutter сам проинструктирует вас, если возникнут проблемы .

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

Перваякоманда,которуювыбудетевыполнятьизкоманднойстроки,ипер-вая,которуювыбудетеделатьсразупослеустановкиSDKвсоответствиисин-струкцияминасайте,–это«flutterdoctor».Большинствокоманд,которыевыбудетевводитьприработесSDK,еслиневсеизних,начинаютсясflutter,кото-рыйфактическиявляетсяисполняемымфайлом,напримерdoctor–этоодна

Page 25: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

31

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

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

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

Android StudioЕщераз,инструкциинасайтеFlutterсопровождаютвасиимеютнезначитель-ныеразличиядлякаждойОС,нокактольковыустановилиAndroidStudio,за-пуститееёивоспользуйтесьмастеромнастройки.ЭтозагрузитAndroidSDK,образыэмулятораивсенеобходимоедляегоработы.Затемустановитеспеци-альныеплагиныDartиFlutter,вдокументацииэтоподробноописано.

Есливыпродолжитеследоватьинструкциям,запуститсяпроцессподклю-чениявашегоAndroidтелефонаилипланшетаккомпьютеру,ноубедитесь,чтоflutter doctorеговидит.Однаковыможетепропуститьэтотшаг!Конечно,еслиувасестьустройствоAndroid,тонеобходимостьвэмуляторепропадает.

ОднакоесливыпредпочитаетеiOSилиесливамненравитсяиспользоватьреальноеустройствоприразработкекодаFlutter–янеподключаюсвойте-лефон,–тогдамоепредложениесостоитвтом,чтобывойтивAndroidStudio,запуститьменеджерAVD(AndroidVirtualMachine),которыйвыможетенайтивменюконфигурациинаэкранезапускаисоздатьсебевиртуальноеустрой-ствоAndroid.ЯпредлагаюсоздатьвиртуальноеустройствоPixel_2,используяуровеньAPI28(убедитесь,чтовыустановилиданнуюверсиюAPI),изадатьемуразрешение1080×1920(420dpi)соперационнойсистемойAndroid9.За-темвыберитеобразx86 (x86_64).Еслиговоритьопроизводительности,вир-туальныеустройстваAndroidдолгоевремяимелиплохуюрепутацию,носей-часэтоттипвиртуальныхустройствработаетисключительнохорошо,дости-гаяпочтинативнойпроизводительностивбольшинствеслучаев.Хотяэтонеимеетзначения,идемдальшеинастроимегоSD-картуна512МБ.Значенияпоумолчаниюдолжнысоответствоватьвашимжеланиям,ноуровеньAPIитиппроцессора–этоключевыеаспекты.

Когдавсёбудетготово–запускаемкодFlutterнаэмуляторе.ИливыможетесделатьвсеэтоизкоманднойстрокиспомощьюSDK.МыжевданнойкнигебудемделатьэтовAndroidStudio.

Обратитевнимание,чтоесливыповторнозапуститеflutter doctor,онвсеравнобудетсообщатьопроблеме,аименночтооннеможетнайтиустройствоAndroid,предполагая,чтовиртуальноеустройство,котороевысоздали,нера-ботает.Ноесли flutterdoctorобнаружитего,онвыдаствамсправку,чтовсехорошо.Наконец,есливывидитесообщениеотом,чтоэмуляторнезапущен,приусловиичтореальноеустройствоAndroidподключеноиэтоединственнаяпроблема,окоторойсообщаетflutterdoctor,товыможетенеобращатьнанеевнимания.

Page 26: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

32

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ЕсливассейчасинтересуетiOS,пожалуйста,успокойтесь!Хотьмыисполь-зуемAndroidStudio,этоникоимобразомнеозначает,чтовсеэтонепримени-модляiOS.ОбiOSнеобходимознатьвпервуюочередьто,чтоесливыхоти-тепротестироватьреальноеустройствоiOSилисоздатьсвоеприложениедляпродажи,вампонадобитсякомпьютерMacиAppleXcodeIDE.Приложениядляпродажинерассматриваютсявэтойкниге,хотя,будьтодляiOSилиAndroid,эмуляторотличносоответствуетнашимзадачам.

Типичное приложение «Hello, World!»Есливыпродолжитеследоватьинструкциинавеб-сайте,топоследнимшагомстанетсозданиенебольшогоприложенияFlutter.Документациятамотличная,нояпредлагаюпропуститьееипозволитьмнепровестиваспоэтомупутиса-мому.

ПервымшагомнеобходимопозволитьAndroidStudio(всочетаниисFlutterSDK)создатьприложениедлянас.Процессдовольнопрост,икактолькомызапустимэтобазовоеприложениенанашемвиртуальномустройстве,мыне-многоизменимего,чтобывымогливидетьгорячуюперезагрузкунаглядно.

Носначаладавайтесоздадимпроект!ПрипервомзапускеAndroidStudioвыувидитеокно,какпоказанонарис.1-1.

Рисунок 1-1. Первый шаг в Android Studio

Page 27: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

33

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

ВидитестрочкуStart a new Flutter Project?Этото,чтонужно,кликайте!Выуви-дитеначальныйэкранмастерановогоприложения,какпоказанонарис.1-2.

Рисунок 1-2. Выберите тип проекта Flutter, который хотите создать

СуществуетчетыретипапроектовFlutter,которыевыможетесоздать:

• Flutter Application(егомыбудемиспользоватьвэтойкниге);

• Flutter Plugin (плагин позволяет использовать нативнуюфункциональ-ностьAndroidилиiOSдлявашихприложенийFlutterнаосновеDart);

• Flutter Package(необходимтольковтомслучае,есливыхотитераспро-странятьпользовательскийвиджетнезависимоотприложения);

• Flutter Module(позволяетвстраиватьприложениеFlutterвнативноепри-ложениеAndroid).

ВыберитеFlutter Application и нажмите кнопкуNext (Далее). Откроетсяокно,какпоказанонарис.1-3.

Page 28: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

34

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Рисунок 1-3. Ввод необходимой информации о вашем приложении

Здесьвывведетеинформациюосоздаваемомприложении.Выможетедатьпроектулюбоеназваниеилиописание,атакжеоставитьзначенияпоумолча-нию.ПринеобходимостиобновитеполеProject location(илипростоисполь-зуйтезначениепоумолчанию).Вывидитеэтуошибкувнизу?Непугайтесь,выужевыбралинужныйпуть.Ноесливывидитеэто,тоAndroidStudioещенезнает,гденаходитсяFlutterSDK,ивамнеобходимоегоуказать.Простопе-рейдитекSDK,которыйвыдолжныбылиустановитьранее,иубедитесь,чтоAndroidStudioэтимдоволен(ошибкаисчезнет),иснованажмитекнопкуNext,чтобыперейтикэкранусрис.1-4.

Page 29: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

35

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Рисунок 1-4. Окончательная информация о проекте

Этотэкрантребуетнемногобольшеинформации,впервуюочередьдоменкомпании.Еслиуваснетдомена,товыможетепоместитьлюбоезначение,ко-тороевамнравится.ТебязовутJim?Тыможешьввести«Jim»!Тыможешьна-писать«Jim»,дажееслиэтонетвоеимя,хотяэтобылобынемногостранно.Обратитевнимание,чтополноеимяпакетасостоитизназванияприложенияидоменавашейкомпании,введенногонапоследнемэкране.Этоимяпакетадолжнобытьуникальным,есливыхотитеопубликоватьприложениевмага-зинеприложений,хотядлянашеготестированияздесьэтонеимеетзначения.

Примечание. Вы также можете увидеть поле Sample Application, в зависимости от версии Android Studio и установленного плагина Flutter . Это для того, чтобы мастер сгенерировал образец кода для вас, если хотите, но нам это не нужно .

Наконец, выберите язык платформы, оставляя Kotlin неотмеченным, таккакSwiftбудетнаиболееподходящим.Этоотноситсякбазовомуязыкуплат-формы,используемомуподоберткамиFlutter,иесливынесобираетесьвзаи-

Page 30: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

36

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

модействоватьснативнымкодомприложения,вам,поидее,должнобытьбезразницы.Вконечномсчетеэтонеимеетзначениядляцелейкниги.

ТакчтонажмитекнопкуFinish,иAndroidStudioпокажетвампростоепри-ложениеFlutter.Этоможетзанятьнесколькоминут,поэтомупроверьтестро-кусостояниявнизу,чтобыубедиться,чтовсезадачивыполнены.Когдавсёбу-детготово,посмотритевверхнюючастьAndroidStudio,напанельинструмен-тов,инайдитевыпадающийэлемент,вкоторомперечисленыподключенныеустройства,какпоказанонарис.1-5.

Рисунок 1-5. Выпадающий список устройств в Android Studio

Выдолжны увидеть созданныйранее эмулятор. Выберите его, и, если онещенезапущен,ондолжензапуститьсявближайшеевремя.Кактолькоэтопроизойдет,нажмитеназначокRun(зеленуюстрелкурядомсвыпадающимспискомmain.dart)–этоточказапускаприложения.Подождите,покаприло-жениебудетсобрано,развернутоизапущенонаэмуляторе(взависимостиотвашеймашиныэтоможетзанятьдоминуты,поэтомубудьтетерпеливы–про-цессускоритсяпослепервойсборки).Выдолжныувидетьвэмуляторечто-товродерис.1-6.

Page 31: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

37

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Рисунок 1-6. Мое первое приложение Flutter!

Этопростоеприложение,ноономногоепоказывает.Нажмитенакруглуюкнопку со знаком «плюс» (она называется «плавающей кнопкой действия»,илиFloatingActionButton,FAB)иобратитевнимание,чтосчетчикувеличива-етсяскаждымщелчкоммыши.

Получившийся код должен автоматически открываться в Android Studio(еслифайлmain.dartнайденвдиректорииверхнегоуровня)ибытьследую-щим(я,конечно,удалилкомментариииотформатировалего,чтобыонлучшевыгляделвпечатномварианте):

import‘package:flutter/material.dart’;

voidmain()=>runApp(MyApp());

classMyAppextendsStatelessWidget{

@override Widgetbuild(BuildContextcontext){ return MaterialApp( title:‘FlutterDemo’, theme:ThemeData( primarySwatch:Colors.blue,

Page 32: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

38

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ ), home:MyHomePage(title:‘FlutterDemoHomePage’), ); } }

classMyHomePageextendsStatefulWidget{

MyHomePage({Keykey,this.title}):super(key:key);

finalStringtitle;

@override _MyHomePageStatecreateState()=>_MyHomePageState(); }

class_MyHomePageStateextendsState<MyHomePage>{

int_counter=0;

void_incrementCounter(){ setState((){ _counter++; }); }

@override Widgetbuild(BuildContextcontext){ return Scaffold( appBar: AppBar( title:Text(widget.title), ), body:Center( child:Column( mainAxisAlignment:MainAxisAlignment.center, children:<Widget>[ Text( ‘Youhavepushedthebuttonthismanytimes:’, ), Text( ‘$_counter’, style:Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton:FloatingActionButton( onPressed:_incrementCounter, tooltip:‘Increment’,

Page 33: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

39

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ child:Icon(Icons.add), ), ); }}

Хотяздесьнетакмногокода,затоонмногоделает.Думаю,покавамнедо-статочнознаний,чтобыполностьюразобратьсявпроисходящем,ведьмыещенеговорилиоDartнастолькоподробно.Ноянехочуоставлятьвасабсолютновневедении,такчтоестьнесколькоключевыхмоментов,которыеяразъясню.

Во-первых,обратитевнимание,чтоосновнаяточкавходакаждогоприложе-нияFlutterявляетсяметодомmain().Вmain()вызываетсяметодrunApp(),кото-рыйвозвращаетвиджетверхнегоуровня.Вначалеиерархиивсегдаестьвиджет,которыйсодержитвсеостальные,здесьэтоэкземплярклассаMyApp.Этотклассявляетсявиджетомбезсостояния,поэтомуединственнаяегозадача–предоста-витьметодbuild().Виджет,возвращаемыйизнего(помните:build()–всегдавозвращающийвиджет,вкотороммогутбытьдочерниеэлементы,амогутинебыть), – это экземпляр MaterialApp, который является виджетом, предостав-леннымFlutter (этоможноувидетьв самомначаленашегокода).Мыпогово-римобэтомвиджетевглаве3,когдабудемподробнеерассматриватьвиджетыFlutter,ноглавное,чтоонобеспечиваетбазовуюинфраструктурудляприложе-нияMaterial.Каквидите,мызадалиназваниеводномизаргументовконструк-тораMaterialApp,этоназваниевыувидитевстрокесостояния(StatusBar)вашегоприложения.ТакжевыможетеустановитьтемудляприложенияFlutterипредо-ставитьподробнуюинформациюоней,напримеросновнойцвет,которыйонаиспользует,унасонсиний.

НашвиджетMaterialAppсодержитодиндочернийэлемент,которыйпред-ставленэкземпляромклассаMyHomePage.

КлассMyHomePageопределяетвиджетссостоянием,такчтонампонадобитсядвакласса,класс«core»,которыйнаследуетсяотStatefulWidget,икласссосто-яния,связанныйсним,наследуетсяотState.

Влюбомслучае,методbuild()этоговиджетасновавозвращаетединствен-ныйвиджет,наэтотразScaffold.Нонезацикливайтесьнаэтом,потомучтовглаве3мыразберемкаждыйизних.Есливдвухсловах,тоScaffoldобеспе-чиваетфундаментальныйвизуальныймакетдляприложения,включаятакиеэлементы,какстрокасостояния(AppBar–этофактическивиджет),гденахо-дитсяназвание.Scaffoldтакжеобеспечиваетмеханизмы,позволяющие«за-цепить» FAB, – экземпляр виджета FloatingActionButton передается в кон-структорScaffold.

Другойаргумент,переданныйвконструкторScaffold,–этотело,вкотороемыдобавляемдругиевиджетывкачестведочерних.Здесьвыможетенаблю-датьмантру«всеэтовиджет»вдействии,потомучтоунасестьцентральныйвиджет,которыйявляетсяконтейнернымвиджетом,который–каквыужедо-гадались–центрирует свойдочернийэлемент.В этомслучаедочернимяв-ляется виджетColumn, которыйразмещает уже своихдетей в одну колонну.

Page 34: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

40

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Column содержитдвадочернихвиджетаText–одиндлястатическоготекста«Youhavepushedthebuttonthismanytimes:»,адругойдляотображенияколи-честванажатийкнопки.

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

Горячая перезагрузка: вот что я люблю!Здесьвсестановитсяневероятнокрутым!Убедитесь,чтоувасестьприложе-ние,работающеевэмуляторе,азатемперейдитекAndroidStudioинайдитеэтустрокукода:

Text( ‘Youhavepushedthebuttonthismanytimes:’,),

Итак,выможетеизменитьданныйтекст,поменяв«button»на«FAB»иза-жавCtrl+S,иливыберитеSave AllвменюFile.Теперьнаблюдайтезаэмулято-ром,ипочтисразувыувидите,чтовашеизменениеотражаетсянаэкране(этоможетзанятьнесколькосекунд,новсёжебыстрее,чемприпервомзапуске).

Оченькруто,неправдали?Горячаяперезагрузкаработаеттольковрежимеотладки,вкоторомвына-

ходитесь;этоможнопонятьблагодаряотладочномубаннерувправомверх-немуглуприложения.Вэтомрежимевашеприложениефактическиработа-етввиртуальноймашинеDart (VM), анекомпилируетсяв собственныйкодпроцессора,чтопроисходит,когдавысоздаетереальноеприложение(да,вашеприложениебудетработатьмедленнееврежимеотладки).Горячаяперезагруз-каработаетпутемобновленияизмененныхфайловисходногокодавужера-ботающуювиртуальнуюмашинуDart,накоторойразмещаетсявашеприложе-ние.Когдаэтопроисходит,VMобновляетклассы,которыеизменились,обнов-ляялюбыеизмененныеполяиметоды.ЗатемструктураFlutterинициируетперестроениедеревавиджетов,ивашиизмененияотражаютсяавтоматиче-ски.Вамненужнопересобиратьилиперезапускатьчто-либо;всепроисходитавтоматическипомеренеобходимости,чтобывашиизменениябылиотобра-женынаэкранекакможнобыстрее.

Времяотвременивыможетеобнаружить,чтоизменениенеприводиткпе-резагрузке,какожидалось.Еслиэтопроизойдет,первое,чтонужнопопробо-вать,–этонажатьназначокгорячейперезагрузкинапанелиинструментов,которыйнарис.1-7выглядиткакмолния(вытакжеможетенайтиопциюго-рячейперезагрузкивменюRunссоответствующейгорячейклавишейCtrl+/).

Page 35: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

41

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Рисунок 1-7. Значок горячей перезагрузки в Android Studio

Это должно помочь вам. Также обратите внимание на консоль, котораядолжнанаходитьсявнижнейчастиAndroidStudio,тамвыувидитеследующеесообщение:Performing hot reload...Reloaded1of448librariesin2,777ms.

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

Обратитевнимание,есливынажалинаFABнесколькораз,азатемизмени-литекст,текущеесостояниеприложенияпродолжитсуществование.Другимисловами,количествоповторныхнажатийнакнопкусохранитсяпослегорячейперезагрузки(hotreload).Этопозволяетлегкоизменятьпользовательскийин-терфейсимгновенноотображатьтекущеесостояние,такчтовыможетебы-строипростосверятьвашуверсткусдизайном.Ночто,есливыхотите,чтобысостояниенесохранялось?Тогдавы,вероятно,захотитевыполнитьгорячийперезапуск(restart).Поэтомувамследуетсделатьэтовручную(вотличиеотгорячейперезагрузки,котораяпроисходитавтоматически,когдавывноситеизменениявкодисохраняетеего),выбравопциюHot restart(горячийпереза-пуск–неперезагрузка)вменюRunилинажавсоответствующуюгорячуюкла-вишу(Ctrl+Shift+/).

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

Вы,естественно,можетеперезапускатьсборкувлюбоевремя(этопроисхо-дитпокомандеRun),нокаждыйразвыбудетедожидатьсякомпиляции,чтоникапелькинеэкономитвашевремя.Горячийперезапуск(restart)сработаетпочтитакжебыстро,какигорячаяперезагрузка(reload),потомучтоработыонделаетнамногоменьше,нодостигаетпримернотогожеэффекта.

Надеюсь,вывидите,наскольковыможетебытьэффективны,используягоря-чуюперезагрузку.Мнекажется,выоценитеэто,когдапознакомитесьсFlutterпоближе!

Page 36: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

42

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Базовая структура приложения FlutterОднаизпоследнихтем,которойякоснусьвовступительнойглаве,–этообщаяструктураприложения,котороебылосозданодлявас.Нарис.1-8вывидитепервичнуюструктурукаталога.

Рисунок 1-8. Первичная структtура каталога проекта

Page 37: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

43

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

Каквидите,существуетпятькаталоговверхнегоуровня.Атеперьподроб-нееокаждомизних:

• android–содержитспецифическийдляAndroidкодиресурсы,такиекакзначки приложений, код Java, а также конфигурациюGradle и ресурсы(GradleявляетсясистемойсборкиAndroid).Насамомделеэтофактиче-скицелыйпроектAndroid,которыйвыможетепостроитьсиспользова-ниемстандартныхинструментовAndroid.Побольшомусчету,вамнуж-ноизменятьтолькозначки(которыенаходятсявкаталогахandroid/app/src/main/res,гдекаждыйподкаталогимеетразноеразрешение)и,вза-висимостиоттого,чтоделаетвашеприложение,файлAndroidManifest.xmlвandroid/app/src/main,гдевыможетеустановитьспециальныесвой-стваприложениядляAndroid;

• ios – как и android, этот каталог содержит код проекта, специфичныйдля iOS. Критическим содержимым здесь является каталог ios/Runner/Assets.xcassets, в котором находятся значки для вашего приложения,ифайлInfo.plistвios/Runner,которыйслужиттойжецели,чтоифайлAndroidManifest.xmlдляприложенийAndroid;

• lib–хотясначалаэтоможетпоказатьсястранным,этоместо, гдебудетжитьвашкод!Выможетеотносительносвободноорганизовыватьсвойкод,создаваялюбуюструктурукаталогов,хотявампонадобитсяодинфайл,ко-торыйслужитточкойвхода,ибольшуючастьвремениимбудетmain.dart,созданныйавтоматически;

• res–этоткаталогсодержиттакиересурсы,какстрокидляпереводаваше-гоприложениянаиностранныеязыки.Новэтойкнигемынебудемиметьснимидело;

• test–здесьвынайдетеDart-файлыдлятестированиявашегоприложе-ния.FlutterпредоставляетутилитуWidgetTester,котораяиспользуетав-томатическиетесты,чтобыподтвердитьфункциональностьвашихвид-жетов.Мынебудемснимработать,такжекакисres,потомучтоэтонео-бязательнаячастьразработкиFlutter,окоторойотдельноможнонаписатьцелуюкнигу!Тестирование–это,конечно,важно,нопокавыненаучи-тесьписатьприложенияFlutter,вамбудетнечеготестировать,аэтакнигафокусируетсянапервойчастивашегопути.

Хотьони скрытпоумолчаниювAndroidStudio, естьтакжекаталог.idea,вкоторомхранитсяинформацияоконфигурацииAndroidStudio,поэтомувыможетеегоигнорировать(обратитевнимание,чтоAndroidStudioосновананаIDEIntelliJIDEA,отсюдаиназвание).Существуеттакжескрытыйкаталогсбор-ки, содержащий информацию, которуюиспользуютAndroid Studio и FlutterSDKдлясозданиявашегоприложения.Номыпроигнорируемиэто.

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

Page 38: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

44

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

пределамикаталогаlib(всеостальноенаскриншотевамненужнознатьвооб-ще),иэто:

• .gitignore–файлуправленияверсиямиGitиспользуется,чтобызнать,ка-киефайлыигнорироватьизуправленияверсиями.ИспользованиеGitсо-вершеннонеобязательнопринаписанииприложенийFlutter,ноэтотфайлгенерируетсявлюбомслучае.Управлениеверсиями–этото,чтонесмо-жетохватитьдажецелаякнига,поэтомувыможетеигнорироватьданныйфайл;

• .metadata–данные,которыеAndroidStudioотслеживаетввашемпроек-те.Выможетеигнорироватьиэто,таккаквыникогданебудетередакти-роватьихсамостоятельно;

• .packages–уFlutterестьсвойсобственныйменеджерпакетовдляуправ-ления зависимостями в вашем проекте. Этот менеджер пакетов назы-ваетсяPub,иониспользуетсядляотслеживаниязависимостейввашемпроекте.Вынебудетевзаимодействоватьсниминапрямуюилидажена-прямуюсPub,поэтомуеготожеможнооставитьбезвнимания;

• *.iml–этотфайлдолженбытьназванвчестьвашегопроектаиявляетсяфайломконфигурациипроектаAndroidStudio.Выникогданебудетере-дактироватьегонапрямую,такчтоигнорируем;

• pubspec.lockиpubspec.yaml–выкогда-нибудьработалисNPM?Знако-мы с package.json ифайлами package-lock.json, которые он использует?Ну,этотежевещи,нодляPub!ЕсливынезнакомысNPM,pubspec.yaml–этото,каквыописываетесвойпроектдляPub,включаяегозависимости.Файлpubspec.lock–этовнутреннийфайлPub.Выопределенноможетередактироватьpubspec.yaml,нонеpubspec.lock,аpubspec.yamlмыпозжеподробнорассмотрим;

• README.md–файлreadme,которыйвыможетеиспользовать,какхотите.Какправило,этофайлMarkdown–сайты,такиекакGitHub,используютдляотображенияинформацииовашемпроектеприпереходекрепози-торию,гдеэтотфайлнаходитсявкорневомкаталоге.

Самымважнымфайломздесьявляетсяpubspec.yaml,ионодинизнемно-гих,которыевамнужнобудетредактировать,поэтом,есливывсезабыли,еголучшезапомните!Мыдоберемсядонегопозже,когданамнужнобудетдоба-витьзависимостивнашпроект,нонаданныймоментсгенерированногофай-лавполнедостаточнодлянашихнужд.

Еще парочка моментов «под прикрытием»Есливыпосмотритенанекоторыеизфайловвкаталогеios,тозаметитесло-во«Runner».Этоподсказкаотом,какработаютприложенияFlutterприсбор-кеизапускеустановочногопакета.Какотмечалосьранее,горячаяперезагруз-

Page 39: Оглавление · нативных (iOS Swift/ObjectiveC) и кроссплатформенных(Xamarin, Qt, PhoneGap/ HTML5, Unity) мобильных приложений

45

ГЛАВА 1 . FLUTTER: ПЛАВНОЕ ПОГРУЖЕНИЕ

каработает,потомучтоврежимеотладкивашкодзапускаетсяввиртуальноймашине.Однакоприсборкеустановочногопакетаэтотакнеработает.ВашкодкомпилируетсявсобственныйкодARM.Фактическикомпилируетсявбибли-отекудляпроцессораARM,которуювдальнейшемиспользуетнативноепри-ложение,этообъясняет,почемувашкоднаходитсявкаталогеlib.

БиблиотекиFlutterнарядусвашимкодомприложениякомпилируются«дозапуска» (Ahead-Of-Time, AOT) с помощью LLVM (Low-Level Virtual Machine,инфраструктуракомпилятора,написаннаянаC++,котораяпредназначенадлякомпиляциииоптимизациипрограмм,написанныхнаразличныхязыкахпро-граммирования)наiOS.НаAndroidиспользуетсяNativeDevelopmentKit(NDK)для сборки ARM-библиотеки. Эта библиотека включена в так называемый«runner»,которыйявляетсяпростонативнымприложением,которое...подо-ждите,подождите...запускаетвашеприложение.Представьте,чтоэтотонкаяоберткавокругвашегоприложения,котораязнает,какзапуститьприложение,ипредоставляетнеобходимыеусловия.Внекоторомсмыслеrunnerпо-преж-немупредставленвиртуальноймашиной,хотяиоченьтонкой(почтикаккон-тейнерDocker,есливыснимзнакомы).

Наконец,runnerвместесоскомпилированнойбиблиотекойупаковываетсявфайл.ipaдля iOSилифайл.apkдляAndroid,иувасестьполный,готовыйкустановкеилипубликациипакет!Когдаприложениезапускается,runnerза-гружаетбиблиотекуFlutterивашкодприложения,исэтогомоментавсявизу-ализация,ввод/выводиобработкасобытийделегируетсяскомпилированномуприложениюFlutter.

ПРИМЕЧАНИЕ. Это очень похоже на то, как работает большинство кроссплатформенных мобильных игровых движков . Ранее я написал книгу о Corona SDK, библиотеке, которую я очень люблю, она работает очень похожим образом, хотя там используется язык Lua вместо Dart (который, могу поспорить, команда Flutter тоже рассматривала!) . Любопытно, что Google, по сути, черпал вдохновение из игровых движков, чтобы создать Flutter, потому что это доказывает то, что я всегда говорил: если вы хотите быть лучшим программистом, единственный вид проекта, в котором вам следует отточить свои навыки, – это игровой . На этот раз мир получил целую платформу приложений! И если вы еще не заглянули вперед, последние две главы этой книги посвящены созданию игры Flutter, потому что я всегда советую создавать игры!

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

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