Основы Flutter для начинающих (Часть I)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Вступление

Добрый день всем желающим познакомиться с Flutter!

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

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

Результатом нашей работы будет небольшое Flutter приложение, которое будет брать данные из JSONPlaceholder.

Первый шаг - Настройка и установка компонентов

Ну что ж, приступим.

Переходим на страницу установки: Install - Flutter и загружаем Flutter для своей платформы

Затем устанавливаем редактор или IDE по инструкции Set up an editor

Я буду использовать Android Studio IDE от Google.

Для разработки на Android Studio нужно установить Flutter плагин (в инструкции Set up an editor, описано как это сделать).

Второй шаг - Создание проекта

Выбираем Flutter Application

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

Затем указываем package name (используется для того, чтобы идентифицировать наше приложение среди других в Google Play или Apple Store, его впоследствии можно будет изменить, более подробно об Android Application ID или об Apple App ID):

Нажимаем Finish.

Третий шаг - создание первоначальной структуры приложения

Очищаем main.dart файл от ненужного кода:

import 'package:flutter/material.dart';

// main() является главной функцией с которой начинается 
// выполнение приложения
// возвращает виджет приложения
void main() => runApp(MyApp());

// В Flutter все является виджетом (кнопки,списки, текст и т.д.)
// виджет - это отдельный компонент, который может быть отрисован
// на экране (не путать с Android виджетами)
// Наиболее простые виджеты наследуются от StatelessWidget класса
// и не имеют состояния
class MyApp extends StatelessWidget {

	// функция build отвечает за построение иерархии виджетов
  @override
  Widget build(BuildContext context) {
		// виджет MaterialApp - главный виджет приложения, который
  	// позволяет настроить тему и использовать
    // Material Design для разработки.
    return MaterialApp(
    	// заголовок приложения
      // обычно виден, когда мы сворачиваем приложение
      title: 'Json Placeholder App',
      // настройка темы, мы ещё вернёмся к этому
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // указываем исходную страницу, которую мы создадим позже
      home: HomePage(),
    );
  }
}

Затем создаем пакет (код должен быть всегда огранизован, дабы сделать его понятнее):

Называем его pages:

Затем создаем в пакете файл home_page.dart:

И реализуем нашу первую страницу:


import 'package:flutter/material.dart';

// StatefulWidget имеет состояние, с которым
// позже мы будем работать через функцию
// setState(VoidCallback fn);
// обратите внимание setState принимает другую функцию
class HomePage extends StatefulWidget {
  // StatefulWidget должен возвращать класс,
  // которые наследуется от State
  @override
  _HomePageState createState() => _HomePageState();
}

// В треугольных скобках мы указываем наш StatefulWidget 
// для которого будет создано состояние
// нижнее подчеркивание _ используется для того, 
// чтобы скрыть доступ к _HomePageState  из других файлов
// нижнее подчеркивание аналогия private в Java / Kotlin
class _HomePageState extends State<HomePage> {
  
  // функция buil, как мы уже отметили, строит
  // иерархию наших любимых виджетов
  @override
  Widget build(BuildContext context) {
    // В большинстве случаев Scaffold используется,
    // как корневой виджет для страницы или экрана
    // Scaffold позволяет вам указать AppBar, BottomNavigationBar,
    // Drawer, FloatingActionButton и другие не менее важные
    // компоненты (виджеты).
    return Scaffold(
      // мы создаем AppBar с текстом "Home Page"
      appBar: AppBar(title: Text("Home page")),
      // указываем текст в качестве тела Scaffold
      // текст предварительно вложен в Center виджет,
      // чтобы выровнять его по центру  
      body: Center(
        child: Text(
          "Hello, JSON Placeholder!!!",
          // Также выравниваем текст внутри самого виджета Text
          textAlign: TextAlign.center,
          // Theme.of(context) позволяет получить доступ к 
          // текущему ThemeData, который был указан в MaterialApp
          // После получения ThemeData мы можем использовать
          // различные его стили (например headline3, как здесь)
          style: Theme.of(context).textTheme.headline3,
        )
      )
    );
  }
  
}

Обратите внимание на мощь Flutter - мы можем вкладывать различные виджеты друг в друга, комбинировать их и создавать более сложные структуры

Четвертый шаг - запуск

Ну что ж, пора испытать наше приложение.

Не забудьте импортировать HomePage в main файл:

import 'pages/home_page.dart';

Важный момент: старайтесь использовать относительный путь, когда импортируете файлы своего проекта, вместо подобного:

import 'package:json_placeholder_app/pages/home_page.dart';

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

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

Переходим к запуску, выбираем устройство на котором будет выполняться приложение (в данном случае я использую реальное устройство, мой Honor 30i), и нажимаем Run:

Та дам!

Если вас раздражает надпись DEBUG в правом верхнем углу, то её можно убрать:

import 'package:flutter/material.dart';

// main() является главной функцией с которой начинается 
// выполнение приложения
// возвращает виджет приложения
void main() => runApp(MyApp());

// В Flutter все является виджетом (кнопки,списки, текст и т.д.)
// виджет - это отдельный компонент, который может быть отрисован
// на экране (не путайте с Android виджетами)
// Наиболее простые виджеты наследуются от StatelessWidget класса
// и не имеют состояния
class MyApp extends StatelessWidget {

	// функция build отвечает за построение иерархии виджетов
  @override
  Widget build(BuildContext context) {
    // виджет MaterialApp - главный виджет приложения, который
    // позволяет настроить тему и использовать
    // Material Design для разработки.
    return MaterialApp(
      // заголовок приложения
      // обычно виден, когда мы сворачиваем приложение
      title: 'Json Placeholder App',
      // убираем баннер
      debugShowCheckedModeBanner: false,
      // настройка темы, мы ещё вернёмся к этому
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      // указываем исходную страницу, которую мы создадим позже
      home: HomePage(),
    );
  }
}

Также обратите внимание, когда вы запустите приложение, вы можете использовать hot reload:

Hot Reload позволяет буквально за 2-5 секунд внести изменения, когда ваше приложение выполняется.

Это довольно приятная опция, которая ускорит вашу разработку.

При каждом вызове Hot Reload происходит перезапуск build функции. (вся иерархия виджетов перестраивается)

Будьте внимательны: не во всех ситуциях Hot Reload срабатывает и изменения отражаются в приложении, поэтому в таких ситуациях нужно перезапускать приложение полностью.

Также есть довольно интересный факт: размер отладочного приложения на Flutter с одним экраном, которое мы только что создали:

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

Отладочное приложение содержит много дополнительной информации, а также к этому добавляется поддержка Hot Reload.

Четвертый шаг - использование состояния

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

Ну что ж попробуем реализовать небольшую анимацию которая будет запускаться по кнопки:


import 'package:flutter/material.dart';

// StatefulWidget имеет состояние, с которым
// позже мы будем работать через функцию
// setState(VoidCallback fn);
// обратите внимание setState принимает другую функцию
class HomePage extends StatefulWidget {
  // StatefulWidget должен возвращать класс,
  // которые наследуется от State
  @override
  _HomePageState createState() => _HomePageState();
}

// В треугольных скобках мы указываем наш StatefulWidget
// для которого будет создано состояние
// нижнее подчеркивание используется для того, чтобы 
// скрыть доступ к _HomePageState из других файлов
// нижнее подчеркивание - аналогия private в Java / Kotlin
class _HomePageState extends State<HomePage> {

  // добавим переменную, которая будет нашим состоянием
  // т.к. _counter мы будем использовать только внутри нашего
  // класса, то сделаем его недоступным для других классов
  // _counter будет хранить значение счетчика
  var _counter = 0;

  // build как мы уже отметили, строит
  // иерархию наших любимых виджетов
  @override
  Widget build(BuildContext context) {
    // В большинстве случаев Scaffold используется
    // как корневой виджет для страницы или экрана
    // Scaffold позволяет вам указать AppBar, BottomNavigationBar,
    // Drawer, FloatingActionButton и другие не менее важные
    // компноненты (виджеты).
    return Scaffold(
      // мы создаем AppBar с текстом "Home page"
      appBar: AppBar(title: Text("Home page")),
      // указываем текст в качестве тела Scaffold
      // текст предварительно вложен в Center виджет,
      // чтобы выровнять его по центру
      body: Center(
        // добавляем AnimatedSwitcher, который и будет управлять
        // нашей анимацией
        child: AnimatedSwitcher(
          // обратите внимание: const указывает
          // на то, что нам известно значение Duration во время
          // компиляции и мы не будем его менять во время выполнения
          // класс Duration позволяет указать задержку в разных
          // единицах измерения (секунды, миллисекунды и т.д.)
          duration: const Duration(milliseconds: 900),
          // AnimatedSwitcher создает reverse эффект,
          // то  есть эффект возврата анимации к первоначальному
          // состоянию, что выглядит не всегда красиво,
          // поэтому я указал reverseDuration в 0
          // вы можете поэкспериментировать с этим значением
          reverseDuration: const Duration(milliseconds: 0),
          child: Text(
            // вывод значения счетчика
            // при каждой перерисовки виджетов _counter 
            // увеличивается на единицу
            "$_counter",
            // здесь самое интересное
            // когда мы изменяем значение _counter
            // и вызываем функцию setState, компоненты
            // перерисовываются и AnimatedSwitcher сравнивает
            // предыдущий key своего дочернего виджета с текущим,
            // если они не совпадают, то вопроизводит анимацию
            key: ValueKey<int>(_counter),
            // Также выравниваем текст внутри самого виджета Text
            textAlign: TextAlign.center,
            // Theme.of(context) позволяет получить доступ к
            // текущему ThemeData, который мы указали в MaterialApp
            // После получения ThemeData мы можем использовать
            // различные его стили (например headline3, как здесь)
            style: Theme.of(context).textTheme.headline3,
          ),
        )
      ),
      // добавляем кнопку
      // FloatingActionButton - круглая кнопка в правом нижнем углу
      floatingActionButton: FloatingActionButton(
        // указываем иконку
        // Flutter предлагает нам большой спектр встроенных иконок
        child: Icon(Icons.animation),
        onPressed: () {
          // наконец то мы дошли до функции setState
          // которая даст сигнал, что пора перерисовывать 
          // наши виджеты. 
          // здесь мы просто увеличиваем наш счетчик
          setState(() {
            _counter++;
          });
        },
      ),
    );
  }

}

Выполняем приложение:

Та дам! Выглядит здорово!

Заключение

Статья получилась достаточно информативной и по моему мнению полезной для новичков.

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

Примерный план:

1) Часть 1 (текущая статья) - введение в разработку, первое приложение, понятие состояния;

2) Часть 2 - BottomNavigationBar и Navigator;

3) Часть 3 - MVC. Мы будем использовать именно этот паттерн, как один из самый простых;

4) Часть 4 - http пакет. Создание Repository класса, первые запросы, вывод списка постов;

5) Часть 5 - Работа с картинками, вывод картинок в виде сетки, получение картинок из сети, добавление своих в приложение;

6) Часть 6 - Создание своей темы, добавление кастомных шрифтов и анимации;

7) Часть 7 - Немного о тестировании;

Надеюсь, что я смогу принести вам пользу и вы не закидаете меня тухлыми помидорами))

Все пожелания в комментариях)

До скорой встречи!

Источник: https://habr.com/ru/post/560008/


Интересные статьи

Интересные статьи

Это - отдельное руководство, описывающее ещё один способ получить личный прокси-сервер shadowsocks бесплатно и служащее продолжением к моей предыдущей статье. В этот раз ...
Книга Мир после капитала американского инвестора немецкого происхождения Альберта Венгера — один из наиболее значимых текстов об экономике после капитализма.Это...
Привет, Хабр! Представляю вашему вниманию перевод статьи "How does a relational database work". Когда дело доходит до реляционных баз данных я не могу не думать, что чего-то не хватае...
Но если для интернет-магазина, разработанного 3–4 года назад «современные» ошибки вполне простительны потому что перед разработчиками «в те далекие времена» не стояло таких задач, то в магазинах, сдел...
Эта публикация написана после неоднократных обращений как клиентов, так и (к горести моей) партнеров. Темы обращений были разные, но причиной в итоге оказывался один и тот же сценарий, реализу...