
Содержание статьи
Flutter – новинка Google открытый источник набор инструментов, который помогает разработчикам создавать приложения для iOS и Android только с помощью одна кодовая база. Программы Flutter написаны на языке программирования Dart и компилируются родной кода, поэтому производительность действительно великолепна.
В этом учебнике я покажу вам, как использовать Flutter для создания приложения, показывающего текущую цену различных криптовалют. Я расскажу вам об основах Flutter и Dart.
Прежде чем начать, установите Flutter и плагин редактора Flutter, если вы этого еще не сделали. Установка должна быть простой, но если вы столкнетесь с проблемами, вы можете оставить комментарий к этой публикации, и я буду рад помочь.
Для этого учебника я буду использовать Android Studio, но вы также можете использовать IntelliJ или Visual Studio Code.
Также требуется определенный опыт объектно-ориентированного программирования (ООП). Расслабься! Вам не нужен многолетний опыт – если вы знаете, что такое классы и объекты, у вас все хорошо.
Давайте начнем
В Android Studio или IntelliJ нажмите Файл меню -> новый -> Новый Флаттер Ппроект. Если вы не видитеe the New Flutter Project, убедитесь, что вы установили плагин Flutter. Если вы используете Visual Studio Code, выполните следующие действия, чтобы создать новый проект.

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

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

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

Вызываемый файл main.dart
была создана в lib
папку. Он содержит код демонстрационной программы. Поскольку мы будем создавать нашу программу с нуля, откройте main.dart
файл и удалите/очистите весь код в нем.
Если ваш проект включает a test
каталог, содержащий файл widget_test.dart
, удалите этот файл перед продолжением. Он содержит тесты для кода, который мы только что удалили.
Программы Flutter написаны на языке программирования Dart. The main.dart
файл является исходным файлом Dart (.dart
расширение). Конвенция Dart подразумевает именование исходных файлов с помощью lowercase_with_underscores
.
Давайте начнем писать код Dart. Мы начнем с традиции программирования: печать Hello World!
Для этого нам придется создать что-то под названием main
функция. The main
Функция – это функция верхнего уровня, которая есть в каждой программе Flutter и служит точкой входа в вашу программу. Подумайте об этом как о входе в дом.

Когда вы запускаете приложение на устройстве, выполнение начнется с основной функции. Давайте создадим простой main
поэтому введите следующий код в свой main.dart
файл.
Как видите, создавая main
функция проста. Вторая строка содержит main
объявление функции: ее тип возврата (void
) и имя (main
). Основная функция возвращается void
то есть ничего не возвращает.
Третья строка выполняет печать на консоль. Мы называем print
и передать ей строчный аргумент. Заметьте, что в Dart вы можете использовать одинарные кавычки (‘string’
) или двойные кавычки (“string”
) при объявлении строчного литерала.
Для запуска кода нажмите зеленую кнопку запуска (воспроизведение) в верхней части Android Studio или IntelliJ. Убедитесь, что реальное устройство подключено или запущен эмулятор.

После успешного запуска программы вы должны увидеть Hello World! напечатано на консоли.

Но если вы проверите устройство или эмулятор, вы увидите что-то нелестное.

Что ж, это было ожидаемо, поскольку сейчас мы печатаем только на консоли. К пользовательскому интерфейсу программы ничего не добавлено, поэтому он пуст.
Давайте исправим это, добавив некоторые элементы к пользовательскому интерфейсу программы. Наше приложение будет использовать материальный дизайн, поэтому давайте добавим пакет к main.dart
файл, чтобы помочь с этим.
import 'package:flutter/material.dart';
Как и любой современный язык программирования, можно импортировать библиотеку/пакет для использования в своем коде. Здесь мы импортируем material.dart
пакет. Этот пакет содержит код, который помогает нам создать программу со стилистикой материала.
The material.dart
пакет имеет функцию под названием runApp
. The runApp
берет виджет и прикрепляет его к экрану. Ну что такое виджет?

Вы можете думать о виджетах как о просмотрах или элементах пользовательского интерфейса. Это вещи, которые вы видите (а некоторые не видите) при запуске приложения на устройстве. В Flutter вы будете часто использовать виджеты, потому что главная идея состоит в том, что интерфейс вашего приложения состоит исключительно из виджетов.
Flutter уже поставляется с набором мощных виджетов, таких как текст и изображения. The material.dart
пакет, который мы только что импортировали, содержит несколько виджетов материального дизайна, которые мы скоро будем использовать.
Давайте использовать runApp
сейчас, чтобы показать «Hello World!» в центре экрана устройства. Заменить содержимое main
функцию с нижеприведенным кодом.
void main() {
print('Hello World!');
// Runs the MaterialApp widget
runApp(new MaterialApp(
// This is the widget that is displayed first when the application is started normally
home: new Center(
// The Text widget is wrapped in a center widget to center it on the screen
child: new Text('Hello World!'),
),
));
}
Позвольте мне объяснить некоторые новые вещи в коде выше
new
: Чтобы создать объект, вы обычно используетеnew
ключевое слово из a конструктор для класса. (ООП)new MaterialApp()
: здесь мы создаем новый объект виджета под названиемMaterialApp
. TheMaterialApp
Виджет создает ряд полезных вещей, необходимых для программы материального дизайна.home:
: в Dart мы можем четко указать название каждого параметра при вызове функции/конструктора. Виджет передан какhome
Параметр отображается первым, когда приложение запускается нормально.new Center(child: new Text('Hello World!'))
: мы заворачиваем виджет «Текст» в виджет «Центр», чтобы текст был центрирован на экране. Виджет «Текст» является дочерним виджетом «Центр». Да, виджеты могут быть вложенными.

Если вы снова запустите код и откроете устройство, вы получите немного лучший экран.

Круто! Нам удалось показать уродливый текст в центре экрана устройства.
Следующие шаги
Давайте сейчас сделаем несколько шагов вперед. Мы будем получать цены на криптовалюту из API CoinMarketCap. API возвращает массив JSON. Вот образец ответа от API:
[
{
"name": "Bitcoin",
"price_usd": "11525.7",
"percent_change_1h": "-0.18",
...
},
...
]
Мы отправим запрос в API CoinMarketCap и расшифруем JSON из программы. Нам придется добавить несколько новых пакетов к main.dart
файл.
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
Вот обзор новых пакетов:
dart:async
: обеспечиваетFuture
класса, о котором я расскажу подробнее ниже.dart:convert
: обеспечиваетjson
переменная, которую мы будем использовать для декодирования строкового ответа JSON.package:http/http.dart
: Предоставляет функцию, которую мы будем использовать для выполнения запросов HTTP GET.
Давайте добавим новую функцию к main.dart
файл, посылающий запрос в API CoinMarketCap.
Future<List> getCurrencies() async {
String apiUrl="
// Make a HTTP GET request to the CoinMarketCap API.
// Await basically pauses execution until the get() function returns a Response
http.Response response = await http.get(apiUrl);
// Using the JSON class to decode the JSON String
return JSON.decode(response.body);
}
Давайте пройдемся по новому коду
→ Future<List>
: Мы в основном говорим, что getCurrencies()
функция вернет a List
когда-то в будущем. Он сделает HTTP-запрос к API CoinMarketCap и вернет a List
валют после завершения.
The getCurrencies()
функция асинхронная. Если у вас есть определенный опыт работы с JavaScript, вы можете придумать Futures
как Promises
. Я создал изображение ниже, чтобы помочь вам понять Futures
в Dart.



→ async and await
:
Await
Выражения позволяют писать асинхронный код почти так, будь он синхронен. The http.get(url)
функция асинхронная, возвращает a Future<Respon
se> немедленно, когда его вызывают. Мы хотим дождатьсяr the Re
sponse, чтобы мы могли декодировать строку JSON, но мы также не хотим использовать уродливые обратные вызовы.
The await
выражение оценивает http.get(url)
а затем приостанавливает текущую запущенную функцию (getCurrencies()
), пока результат не будет готов – то есть к завершению будущего.
Использовать await
, код должен находиться в функции, обозначенной как асинхронная. Ан async
функция — функция, тело которой обозначено знаком async
модификатор. Когда вы звоните async
она немедленно возвращает Future. Тело функции запланировано для выполнения позже.
Вы можете прочитать больше о async
и await
в Dart здесь.
→ http.get(url)
: делает HTTP-запрос GET в CoinMarketCap API. Эта функция асинхронна и немедленно возвращает Future.
JSON.decode(response.body)
: декодирует строчный ответ JSON.
Давайте проверим getCurrencies()
функцию, которую мы только что создали. Мы делаем это, делая вызов к нему в нашем main
функцию и печать возвращенного значения на консоль.
// Since we are using await within the main function, we have to make it asynchronous too
void main() async {
// Testing the getCurrencies function
// We wait for the currency data to arrive
List currencies = await getCurrencies();
// Before printing it to the Console
print(currencies);
runApp(new MaterialApp(
home: new Center(
child: new Text('Hello World!'),
),
));
Если вы запустите код выше, вы увидите ответ API, напечатанный на консоли.

Что ж, в реальном мире могут произойти плохие вещи. Например, возможно, вы не подключены к Интернету, поэтому запрос CoinMarketCap API не удастся. Для этого учебника мы допустим, что мы находимся в Ваканде.
В рабочей программе вам предстоит решать сбой сети. Вы делаете это, размещая вызов HTTP в a try…catch
блокировать.
Создание пользовательского интерфейса
Теперь, когда у нас есть список валют, давайте создадим пользовательский интерфейс для отображения этого списка.
При написании программ Flutter вы обычно создаете новые классы виджетов. Основная задача виджета состоит в реализации a build
функция, описывающая виджет с точки зрения других виджетов более низкого уровня.
Давайте создадим новый виджет под названием CryptoListWidget. Добавьте следующий код внизу своего main.dart
файл.
class CryptoListWidget extends StatelessWidget {
// This is a list of material colors. Feel free to add more colors, it won't break the code
final List<MaterialColor> _colors = [Colors.blue, Colors.indigo, Colors.red];
// The underscore before a variable name marks it as a private variable
final List _currencies;
// This is a constructor in Dart. We are assigning the value passed to the constructor
// to the _currencies variable
CryptoListWidget(this._currencies);
@override
Widget build(BuildContext context) {
// Build describes the widget in terms of other, lower-level widgets.
return new Text('Hello World!');
}
}
Давайте пройдемся по новому коду выше:
StatelessWidget
: обычно вы создаете виджеты, являющиеся подклассами любогоStatelessWidget
илиStatefulWidget
в зависимости от того, управляет ли ваш виджет любым состоянием. Мы используемStatelessWidget
потому что у нас уже есть наши данные, и мы не будем обновлять их в этом руководстве.final List<MaterialColor> _
цвета: переменныеin a Stateless
Виджет Шоуld be
окончательные (т.е. они постоянны или не изменяются). Вот мы декларируемing a
конечная переменная, содержащая list of Materia
lЦветы. Нижниеc
ore(_) перед тем, как название переменной делает его закрытым (недоступным из других классов).CryptoListWidget(this._currencies)
: Это конструктор для нашего виджета Он назначает список валют, которые мы передаем в конструктор._currencies
переменная.build
функция: метод построения возвращает виджет низшего уровня (Text
), описывающий, как это будет выглядеть.
Давайте заменим текстовый виджет в build
функция выше с новым виджетом под названием Scaffold
. The Scaffold
Виджет реализует базовую структуру визуального макета материального дизайна. Замените build
функцией выше с тем, что ниже.
@override
Widget build(BuildContext context) {
return new Scaffold(
body: _buildBody(),
backgroundColor: Colors.blue,
);
}
Класс Scaffold предоставляет API для показа ящиков, перемещения кнопки действия, нижней панели, панели закусочных и так далее. Позже мы добавим плавающую кнопку действия.

Вы должны получить предупреждение об этом _buildBody()
не определено для класса CryptoListWidget
. Давайте дальше творить _buildBody()
функция внутри CryptoListWidget
класс.
Widget _buildBody() {
return new Container(
// A top margin of 56.0. A left and right margin of 8.0. And a bottom margin of 0.0.
margin: const EdgeInsets.fromLTRB(8.0, 56.0, 8.0, 0.0),
child: new Column(
// A column widget can have several widgets that are placed in a top down fashion
children: <Widget>[
_getAppTitleWidget(),
_getListViewWidget()
],
),
);
}
Синтаксис здесь должен быть знаком. Мы используем два новых виджета:
Container
виджет: АContainer
виджет – это просто контейнер 🙂 (для других виджетов).- Виджет столбцов: A
Column
макеты виджетов список дочерних виджетов в вертикальном направлении. Он имеет параметр под названиемchildren
принимающий список виджетов.
Давайте создадим две функции, которые мы вызывали в _buildBody()
функция. Первый есть _getAppTitleWidget()
.
Widget _getAppTitleWidget() {
return new Text(
'Cryptocurrencies',
style: new TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24.0),
);
}
Эта функция возвращает регулярное значение Text
виджет со стилем, делающим его жирным и белым с размером шрифта 24,0.
Когда мы запускаем приложение, текст будет выглядеть так.

Мы еще не можем запустить приложение, поскольку мы не создали другую функцию под названием _getListViewWidget()
. Давайте быстро создадим его с помощью приведенного ниже кода.
Widget _getListViewWidget() {
// We want the ListView to have the flexibility to expand to fill the
// available space in the vertical axis
return new Flexible(
child: new ListView.builder(
// The number of items to show
itemCount: _currencies.length,
// Callback that should return ListView children
// The index parameter = 0...(itemCount-1)
itemBuilder: (context, index) {
// Get the currency at this position
final Map currency = _currencies[index];
// Get the icon color. Since x mod y, will always be less than y,
// this will be within bounds
final MaterialColor color = _colors[index % _colors.length];
return _getListItemWidget(currency, color);
}));
}
The _getListViewWidget()
возвращает a ListView
виджет, завернутый в a Flexible
виджет. Мы используем ListView.builder
чтобы легко создать список. Проходим в ан itemCount
который уведомляет строителя, сколько валют показать.
The itemBuilder
обратный вызов будет вызван для каждого элемента, и вы должны вернуть новый виджет. В приведенном выше коде мы вызываем функцию под названием _getListItemWidget()
возвращающий виджет.
CircleAvatar _getLeadingWidget(String currencyName, MaterialColor color) {
return new CircleAvatar(
backgroundColor: color,
child: new Text(currencyName[0]),
);
}
Прежде чем мы создадим _getListItemWidget()
давайте быстро создадим отдельные элементы для виджета ListView. Мы хотим, чтобы каждый элемент в ListView выглядел так:

Итак, у нас есть три основных виджета:
- Виджет круглый значок с первым символом названия валюты.
- Текстовый виджет с названием валюты
- Текстовый виджет с изменением цены и процента за 1 час.
Text _getTitleWidget(String currencyName) {
return new Text(
currencyName,
style: new TextStyle(fontWeight: FontWeight.bold),
);
}
Text _getSubtitleWidget(String priceUsd, String percentChange1h) {
return new Text('\$$priceUsd\n1 hour: $percentChange1h%');
}
Давайте создадим виджеты. Для простоты я создал функцию для каждого из них. Первая вызванная функция _getLeadingWidget()
возвращает круглый значок с текстом.
Виджет будет выглядеть так:

Вторая функция вызвана _getTitleWidget
возвращает Text
виджет для наименования валюты.
Третья функция под названием _getSubtitleWidget() возвращает Text
виджет текущей цены валюты и изменения процентов за 1 час.
Оба эти виджета должны выглядеть так:

Давайте завернем все три виджета во что-то под названием a ListTile
виджет. The ListTile
виджет основан на документации Material Design List. Он показывает все три виджета в этом стиле.

Мы создадим новую функцию под названием _getListTile
что возвращает a ListTile
виджет.
ListTile _getListTile(Map currency, MaterialColor color) {
return new ListTile(
leading: _getLeadingWidget(currency['name'], color),
title: _getTitleWidget(currency['name']),
subtitle: _getSubtitleWidget(
currency['price_usd'], currency['percent_change_1h']),
isThreeLine: true,
);
}
Наконец, давайте создадим _getListItemWidget()
. Он собирается вернуться a Container
виджет с верхним отступом 5.0 и a Card
дочерний виджет. Виджет карты имеет ListTile
возвращено _getListTile
как ребенок.
Container _getListItemWidget(Map currency, MaterialColor color) {
// Returns a container widget that has a card child and a top margin of 5.0
return new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Card(
child: _getListTile(currency, color),
),
);
}
Виджет будет выглядеть так.

Мы успешно завершили нашу CryptoListWidget
. Но мы должны обновить main
чтобы отобразить только что созданный виджет вместо Text
виджет.
void main() async {
// Bad practice alert :). You should ideally show the UI, and probably a progress view,
// then when the requests completes, update the UI to show the data.
List currencies = await getCurrencies();
print(currencies);
runApp(new MaterialApp(
home: new CryptoListWidget(currencies),
));
}
Это оно. Вы можете снова нажать кнопку запуска. Если все работает хорошо и вы подключены к Интернету, вы должны увидеть экран, который выглядит так.

В самом деле круто, правда?
Приложение, которое вы видите, будет несколько отличаться от снимка экрана выше:
- Он не имеет плавающей кнопки действия внизу справа.
- Цвет текста изменения за 1 час черный.
Я решил не включать в учебник. Но вы можете проверить репозиторий проекта Github, чтобы узнать, как я смог этого добиться.
Готовое приложение можно скачать здесь.
Спасибо за чтение и надеюсь, что Flutter вам понравится так же, как и мне. Не стесняйтесь оставить комментарий ниже, если у вас возникнут проблемы, предложения и т.д.