Изучите Flutter, создав свое первое приложение Flutter!
В этой статье я собираюсь познакомить вас с вашим первым приложением Flutter. Мы рассмотрим части проекта Flutter, их роли и рассмотрим некоторые фундаментальные концепции состояния, включая различия между StatelessWidgets
и StatefulWidgets
.
Если вы еще не установили Flutter, вот несколько пошаговых видеороликов, которые проведут вас через процесс установки Flutter на Mac, Windows и Linux.
📽 Видеоверсия доступна на YouTube
Создание базового приложения Flutter
Начнем с создания базового приложения. Вы можете сделать это из меню вашего любимого редактора кода, хотя я всегда предпочитаю делать это из терминала:
flutter create flutter_test_app
Эта команда создаст базовое приложение для подсчета, которое при выполнении позволит нам увеличивать числовое значение, нажав кнопку:
Цель этого примера кода — дать вам первое представление о Flutter. Мы будем постепенно идти к пониманию этого шаблона, который нам уже дан.
Файл конфигурации pubspec.yaml
Первое, что мы собираемся рассмотреть, это файл pubspec.yaml
:
Этот файл содержит основные метаданные приложения, перечисляет все зависимости и включает различные параметры конфигурации. Если вы откроете его, вы найдете комментарии к каждому разделу, объясняющие их назначение. Однако для ясности мы удалим эти комментарии, чтобы файл был простым и кратким обзором каждого сегмента:
name: flutter_test_app
description: "You can add a description for your project here."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=3.2.6 <4.0.0'
Разъясним значение каждого параметра:
- Name: представляет имя проекта. Оно служит «внутренним» идентификатором и не является именем, предоставляемым вашим пользователям.
- Описание: это поле позволяет вам предоставить краткое описание цели вашего проекта.
- Publish_to: этот параметр в первую очередь актуален для разработки пакетов. Поскольку эта статья посвящена базовым понятиям, мы оставим ее без изменений.
- Версия: Здесь вы можете указать версию вашего проекта, используя семантическое управление версиями, за которым следует дополнительное целое число. Такая практика позволяет осуществлять контроль версий непосредственно из этого файла, который затем применяется ко всем проектам, специфичным для платформы. Завершающее целое число обычно соответствует коду версии в проектах Android.
- Среда: здесь указывается совместимый диапазон версий Dart SDK для вашего приложения. Если в будущем вы захотите использовать новые версии Dart SDK, возможно, вам будет интересно изменить его, но сейчас мы оставляем все как есть.
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
Следующая часть посвящена зависимостям приложения, которые делятся на два типа: включенные в окончательный пакет приложения (зависимости) и те, которые используются во время разработки, но не включены в окончательный пакет приложения (dev_dependenties
). Чтобы понять это различие, давайте рассмотрим в качестве примера пакет flutter_lints
. Этот пакет помогает в статическом анализе кода, который выполняется локально на вашем компьютере. Нет необходимости, чтобы он был частью окончательного пакета приложения, распространяемого среди пользователей.
После добавленияflutter_lints
в вашиdev_dependentities
и запускаflutter pub get
вы можете проанализировать свой код в соответствии с правилами проверки, заданнымиflutter_lints
, с помощью командыflutter Analysis
. Эта команда проверяет ваш код на наличие проблем на основе правил проверки, определенных пакетом.
Чтобы найти новые пакеты, разработчики Flutter часто посещают https://pub.dev. Предположим, вы хотите выполнить сетевой запрос к удаленному серверу с помощью http-пакета. Вы можете просто добавить его в свои зависимости, а затем выполнить flutter pub get
, чтобы получить пакет и подготовить его к использованию.
Альтернативно вы можете использовать команду flutter pub add http
, чтобы не только загрузить, но и автоматически добавить пакет http
в ваши зависимости. Чтобы добавить пакет в dev_dependenties
, вы должны использовать flutter pub add --dev package_name
.
Экспериментирование с этими методами может помочь вам определить наиболее удобный способ управления пакетами в вашем приложении Flutter.
flutter:
uses-material-design: true
В конце файла есть раздел с надписью "futter
", в котором указана настройка use-material-design: true
. Этот конкретный параметр сообщает Flutter, что наше приложение будет использовать стиль Material Design, предоставляя набор рекомендаций по визуальному дизайну, взаимодействию и анимационному дизайну, разработанный Google.
По мере того, как вы углубляетесь в разработку Flutter, вы столкнетесь с рядом дополнительных конфигураций, которые можно применить в этом файле для дальнейшей персонализации тем и других аспектов вашего приложения.
Кроме того, стоит упомянуть файл pubspec.lock
, важнейший компонент проектов Flutter. Этот файл автоматически создается Flutter, когда вы запускаете такие команды, как flutter pub get
или flutter pub add
. Его основная цель — записать точные версии каждой зависимости, используемой в вашем проекте, на момент выполнения этих команд. Это гарантирует, что ваш проект останется согласованным и стабильным, даже если зависимости будут обновлены в будущем. Отслеживая эти версии, файл pubspec.lock
помогает предотвратить проблему «он работает на моей машине», гарантируя, что каждый разработчик, работающий над проектом, использует одни и те же версии зависимостей, что сводит к минимуму конфликты и проблемы совместимости.
Специфические для платформы проекты во Flutter
Внутри проекта Flutter, помимо файлов pubspec.yaml
и pubspec.lock
, вы увидите несколько каталогов, названных в честь платформ. Эти каталоги: android
, ios
, macos
, linux
и windows
. Это не просто папки; это полноценные собственные проекты для соответствующих платформ.
Сильная сторона Flutter заключается в его способности предоставлять многоплатформенную среду разработки, скрывая сложности деталей реализации для конкретной платформы. Тем не менее, существование этих проектов, ориентированных на конкретную платформу, имеет решающее значение для бесперебойной работы Flutter в различных средах.
Бывают случаи, когда вам нужно погрузиться в нативную разработку в этих каталогах. Часто это тот случай, когда определенная функциональность может быть достигнута только с помощью кода, специфичного для платформы. Именно в таких сценариях становятся необходимыми изменения в исходных частях проекта.
Важно отметить, что вам не обязательно поддерживать все эти каталоги, если ваше приложение не предназначено для всех поддерживаемых платформ. Например, если вы сосредоточены исключительно на Android
и iOS
, вы можете безопасно удалить каталоги Macos
, Linux
и Windows
.
И наоборот, если вы решите расширить доступность вашего приложения для дополнительных платформ, изначально не включенных в ваш проект, Flutter упростит это расширение. Используя команду flutter create
с опцией --platforms
, вы можете добавить необходимые проекты платформы. Например, если вы начинаете с проекта, поддерживающего только Android
и iOS
, а позже решите включить поддержку macOS
, Linux
и Windows
, вы можете выполнить flutter create --platforms=macos
, linux
, windows
. Эта команда создает необходимые каталоги для новых поддерживаемых платформ.
Исходный код вашего приложения: каталог lib.
Мы уже видели основные файлы и каталоги проекта Flutter, хотя я, правда, не перечислил их все, а сейчас описал наиболее важные из них, о которых вам следует знать с самого начала. Теперь давайте перейдем в каталог lib
, место, где находится весь код Dart, составляющий ваше приложение.
Когда вы создаете новый проект, Flutter автоматически создает файл main.dart
в папке lib
. Этот файл содержит исходный код, отвечающий за приложение-счетчик, которое вы увидите, если запустите проект. Если вы войдете, вы увидите комментарии, объясняющие каждый раздел. Как и раньше, мы собираемся исключить эти комментарии и постепенно объясним каждую часть:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
Первая строка представляет импорт material.dart
. Этот импорт важен, поскольку по умолчанию мы используем виджеты Material для создания пользовательского интерфейса.
После этого мы встречаем метод main()
. Каждому приложению Dart, включая Flutter, требуется точка входа, которая предоставляется функцией main()
. Внутри этой функции мы вызываем runApp()
, позволяя приложению запуститься. Мы передаем ему экземпляр MyApp
, который является следующим виджетом, который мы встретим в файле:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
В этом фрагменте представлен виджет MyApp, который служит основным элементом вашего приложения. Он находится на вершине иерархии виджетов и по сути действует как корень, от которого будут разветвляться все остальные виджеты. Приложения Flutter структурированы как обширное дерево виджетов, где каждый виджет может быть родительским или дочерним для других. Здесь MyApp
выступает в качестве начального узла в этой взаимосвязанной структуре.
MyApp
определяется как класс, расширяющий StatelessWidget
. StatelessWidgets
характеризуются отсутствием внутреннего состояния — они не управляют данными, которые изменяются с течением времени. Следовательно, StatelessWidget
не перестраивается в ответ на изменения внутренних данных. Более подробная информация об этом будет предоставлена по мере нашего продвижения.
Каждый StatelessWidget
должен реализовать метод Widget build (BuildContext context)
. В этом методе создается пользовательский интерфейс приложения. В этом примере мы создаем виджет MaterialApp
внутри этого метода. MaterialApp
облегчает разработку приложения в соответствии с рекомендациями Material Design
, включая такие аспекты, как название и тема приложения.
Атрибут home
определяет виджет, который будет отображаться при запуске приложения. Здесь для него установлено значение MyHomePage
— виджет, который идет следующим в файле:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
MyHomePage
— это виджет, похожий на MyApp
, но он наследуется от StatefulWidget
, а не от StatelessWidget
. Это различие вводит два связанных класса: сам MyHomePage
, который настраивает виджет, и _MyHomePageState
, класс, который управляет состоянием виджета, расширяя State.
Причина, по которой_MyHomePageState
начинается с символа подчеркивания (_
), заключается в том, чтобы указать, что этот класс должен быть частным в этом файле.
В классе состояния мы обязаны снова реализовать метод Widget
build(BuildContext context)
. Однако на этот раз это происходит внутри класса состояния, где мы определяем дерево виджетов, составляющее интерфейс счетчика:
- Изначально виджет
Scaffold
отображает базовую структуру нашего экрана, учитывая такие элементы, как панели навигации системы.
AppBar
действует как верхняя панель навигации, где мы указываем заголовок и изменяем цвет фона с помощью тем.
- Тело
Scaffold
содержит виджетCenter
, который обеспечивает центрирование его содержимого на экране. Внутри Центра размещаем Колонку для вертикального расположения виджетов. Этот столбец содержит два виджета «Текст»: один отображает статическое сообщение, а другой — динамическое значение _counter, стилизованное под текущую тему.
- Свойство
floatActionButton
объектаScaffold
использует виджетFloatingActionButton
. Эта кнопка, расположенная в правом нижнем углу, предназначена для увеличения счетчика при каждом нажатии.
Понимание управления состоянием во Flutter
Теперь, когда мы примерно увидели все, что есть в файле main.dart
, давайте по-простому поймем, как Flutter управляет состоянием.
Как я уже говорил, класс _MyHomePageState
отвечает за управление состоянием виджета MyHomePage
. В данном случае у нас есть приложение с числовым значением, которое увеличивается при нажатии кнопки. Это государство. В частности, переменная, определенная в начале класса:
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Когда мы вызываем метод _incrementCounter()
, он вызывает метод setState
, и внутри него увеличивается значение переменной _counter
. Вызывая метод setState
, мы обновляем состояние, сообщая Flutter
, что оно изменилось, и заставляем метод сборки запускаться снова, но на этот раз с обновленным состоянием. Позже во втором виджете типа Text
считывается переменная _counter
для отображения значения на экране.
Это очень упрощенное объяснение управления состоянием во Flutter
. Давайте проведем эксперимент и добавим следующую строку непосредственно перед тем, как сборка вернет Scaffold
:
@override
Widget build(BuildContext context) {
print('State refresh'); // <-- Add this new line
return Scaffold(
Теперь снова запустите приложение и посмотрите журнал вывода. Вы увидите напечатанную строку «Обновление состояния» при запуске приложения, а также при изменении значения счетчика.
Как видите, это самый простой способ управлять состоянием вашего приложения во Flutter. Кроме того, вы также смогли увидеть роль метода сборки и его важность при составлении интерфейса на основе изменений состояния.
Ваше первое приложение во Flutter: ключевые понятия
Если это ваш первый контакт с Flutter, возможно, на данный момент вы немного перенасыщены таким большим количеством информации, не волнуйтесь, я перечислю ключевые моменты, которые мы увидели на протяжении всей статьи.
- Проект Flutter содержит файл
pubspec.yaml
. Он определяет несколько параметров конфигурации, а также список пакетов, используемых проектом.
- Проект Flutter может содержать несколько подкаталогов, названных в честь платформы, например
android
илиios
. Это собственные проекты, которые Flutter использует для запуска на каждой платформе.
- Внутри каталога
lib
мы находим исходный код проекта, именно здесь мы будем писать наши файлы в кодеDart
для создания нашего приложения.
- По своей сути приложение Flutter структурировано как обширная иерархия виджетов. Виджеты могут быть двух типов:
StatefulWidget
, который хранит состояние (переменные, которые могут меняться со временем), иStatelessWidget
, который не хранит состояние.
- Мы можем изменить состояние
StatefulWidget
, используя методsetState
.
В целом это основные базовые моменты, которые вам следует знать, если вы начинаете разрабатывать приложения с помощью Flutter
.
Надеюсь, эта статья была для вас полезна. Не стесняйтесь следить за этим блогом и моим каналом на YouTube, если вы хотите продолжить изучение разработки приложений с помощью Flutter
, а также быть в курсе новостей и других интересных тем, связанных с этой великолепной средой.
Спасибо, что дочитали до этого места, удачного кодирования!