Flutter Widgets — что это, дерево виджетов и build

Автор: IT Sectr Опубликовано: 2026-02-21 Время чтения: 8 мин

Flutter Widgets — базовые строительные блоки пользовательского интерфейса во фреймворке Google Flutter, выпущенном в стабильной версии 1.0 в декабре 2018 года. В Flutter всё — виджет: от экрана и кнопки до отступа и выравнивания. Виджеты образуют дерево (widget tree), которое Flutter рендерит на собственный движок Skia/Impeller, минуя нативные компоненты платформы. По данным Google I/O (2025), Flutter используется более чем в 500 000 приложений в Google Play и App Store. Архитектура Flutter разделяет виджеты на StatelessWidget (неизменяемые) и StatefulWidget (с изменяемым состоянием через State-объект).

Главное

  • Flutter Widgets — все элементы UI во Flutter: от экрана и кнопки до отступа и выравнивания; фреймворк не использует нативные компоненты платформы.
  • StatelessWidget — виджет без изменяемого состояния; отображает данные, переданные через конструктор, и не меняется после сборки (build).
  • StatefulWidget — виджет с изменяемым состоянием, хранящимся в отдельном объекте State, который переживает ребилды.
  • Дерево виджетов (widget tree) — иерархия виджетов, описывающих UI; Flutter преобразует её в Element Tree и Render Tree для рендеринга.
  • BuildContext — контекст сборки, предоставляющий доступ к позиции виджета в дереве, теме, MediaQuery и InheritedWidget.

Что такое Flutter Widgets?

Flutter Widgets — все элементы UI во фреймворке Flutter, реализованные как неизменяемые (immutable) Dart-классы. Виджет — это конфигурация элемента UI: его размер, цвет, положение, обработчики событий. В отличие от Android (XML + View) или iOS (Storyboard + UIView), Flutter не использует нативные компоненты — всё рисуется движком Skia (Android/iOS/Linux) или Impeller (iOS/macOS) на Canvas. Это обеспечивает одинаковый внешний вид на всех платформах без платформенных расхождений. Flutter поставляется с двумя наборами виджетов: Material Widgets (дизайн Google Material Design 3 для Android/веба) и Cupertino Widgets (дизайн Apple HIG для iOS/macOS). Разработчик может комбинировать оба набора в одном приложении. Каждый виджет имеет метод build(), возвращающий дочерний виджет или их композицию — так строится дерево виджетов.

Три дерева Flutter

Flutter оперирует тремя деревьями: Widget Tree (конфигурация, создаётся разработчиком), Element Tree (сопоставление виджета с позицией в дереве, управляется фреймворком), Render Tree (объекты, вычисляющие layout и выполняющие paint). Widget создаёт Element, который создаёт RenderObject. Element переиспользуется при изменении конфигурации (rebuild) — это механизм оптимизации Flutter: если тип виджета и key совпадают, Element не пересоздаётся, а обновляется новая конфигурация. Понимание трёх деревьев — ключ к оптимизации производительности Flutter-приложений.

StatelessWidget: неизменяемые виджеты

StatelessWidget — виджет, который не хранит внутреннее состояние. Он принимает параметры через конструктор и отображает их без возможности изменения после сборки. StatelessWidget идеально подходит для статических элементов: заголовков, иконок, аватаров, списков с фиксированными данными. Метод build() вызывается один раз при создании и при изменении родительского виджета. Поскольку StatelessWidget не имеет состояния, он не требует отдельного State-объекта — build() определён прямо в классе виджета.

dart
import 'package:flutter/material.dart';

class ProfileHeader extends StatelessWidget {
  final String name;
  final String avatarUrl;

  const ProfileHeader({super.key, required this.name, required this.avatarUrl});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        CircleAvatar(
          radius: 24,
          backgroundImage: NetworkImage(avatarUrl),
        ),
        const SizedBox(width: 12),
        Text(
          name,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

ProfileHeader — StatelessWidget, принимающий name и avatarUrl через конструктор. CircleAvatar отображает аватар, Text — имя. Виджет не может изменить эти значения после создания. Использование const конструктора (const ProfileHeader) позволяет Flutter переиспользовать экземпляр виджета при rebuild родителя — это микрооптимизация, рекомендованная для всех StatelessWidget.

StatefulWidget: виджеты с состоянием

StatefulWidget — виджет с изменяемым состоянием, которое хранится в отдельном объекте State. Сам StatefulWidget — неизменяемый (immutable), как и StatelessWidget. Изменяемая часть вынесена в State: State — объект, который создаётся один раз и переживает множественные ребилды виджета. Когда состояние меняется (setState()), Flutter вызывает build() State, обновляя UI. StatefulWidget используется для интерактивных элементов: счётчики, текстовые поля, чекбоксы, анимации, таймеры.

dart
import 'package:flutter/material.dart';

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  int count = 42;

  void _toggleLike() {
    setState(() {
      liked = !liked;
      count += liked ? 1 : -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _toggleLike,
      child: Text(liked ? '♥ $count' : '♡ $count'),
    );
  }
}

LikeButton — StatefulWidget с State-классом _LikeButtonState. Поля liked и count — состояние, которое хранится в State и не сбрасывается при rebuild. setState() уведомляет Flutter о необходимости перестроить UI. Flutter не воссоздаёт State при каждом родительском rebuild — только при изменении конфигурации (key или тип виджета). В IT Sectr мы используем StatelessWidget для отображения и StatefulWidget для интерактивных компонентов, следуя принципу минимизации StatefulWidget до границ мутации.

Дерево виджетов: от Widget до RenderObject

Widget Tree — иерархическая структура виджетов, описывающая UI приложения. Flutter преобразует Widget Tree в Element Tree: каждый Widget создаёт Element, который отслеживает позицию в дереве и связь с RenderObject. Render Tree выполняет layout (определение размеров и позиций) и paint (отрисовку). Element — ключевой оптимизационный слой: если тип виджета и key не изменились при rebuild, Element переиспользуется, обновляя конфигурацию без пересоздания RenderObject. Это обеспечивает производительность Flutter при высокой частоте кадров (60/120 FPS).

dart
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Widgets')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.flutter_dash, size: 80),
            const SizedBox(height: 16),
            const Text(
              'Hello, Flutter!',
              style: TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

Дерево виджетов HomeScreen: Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold — корневой layout-виджет Material Design. Center центрирует дочерний Column. Column располагает детей вертикально с выравниванием по центру (mainAxisAlignment.center). Flutter вычисляет layout сверху вниз (constraints передаются от родителя), а размеры — снизу вверх (sizedByParent или sizing from children).

BuildContext: контекст сборки и доступ к дереву

BuildContext — дескриптор позиции виджета в Element Tree. Каждый метод build() получает BuildContext, через который виджет может получить доступ к:MediaQuery (размер экрана, ориентация, плотность пикселей, safe area), Theme (MaterialThemeData или CupertinoThemeData), Navigator (навигационный стек), ScaffoldMessenger (SnackBar), InheritedWidget (прокидывание данных вниз по дереву). BuildContext не должен сохраняться после завершения build() или использоваться вне синхронного контекста — это приводит к ошибкам «Scaffold.of() called with a context that does not contain a Scaffold». Вместо сохранения context используйте Builder-виджет или паттерн InheritedWidget для доступа к данным.

Key: идентификация виджета в дереве

Key — опциональный параметр конструктора каждого виджета (super.key). Key помогает Flutter идентифицировать виджет при изменении порядка/количества элементов в списке. Без key Flutter сравнивает виджеты по типу и позиции; при добавлении элемента в середину списка без key Flutter переиспользует Element для неправильного виджета, вызывая баги с состоянием (StatefulWidget) и анимацией. Используйте ValueKey (уникальный идентификатор) для списков, ObjectKey (на основе объекта данных), UniqueKey (гарантированно уникальный при каждом rebuild — для форсированного пересоздания).

Каталог виджетов Flutter: Material, Cupertino, Layout

Flutter SDK (стабильная версия 3.3+, Dart 3+) включает 200+ встроенных виджетов, разделённых на категории: Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView), Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable), Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar), Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask), Async (FutureBuilder, StreamBuilder) и Accessibility (Semantics, MergeSemantics, ExcludeSemantics). Layout-виджеты — основа любого Flutter UI: Row для горизонтальных последовательностей, Column для вертикальных, Stack для перекрывающихся элементов, Container с BoxDecoration для декорирования.

КатегорияКлючевые виджетыНазначение
LayoutRow, Column, Stack, Container, Expanded, FlexibleПозиционирование и размеры дочерних элементов
MaterialScaffold, AppBar, Card, Drawer, FAB, TabBarUI-компоненты Material Design 3
CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoButtoniOS-стилизованные компоненты
PaintingOpacity, ClipRect, Transform, DecoratedBox, BackdropFilterВизуальные эффекты и клиппинг
AsyncFutureBuilder, StreamBuilderАсинхронная загрузка данных с UI-состояниями
AccessibilitySemantics, MergeSemanticsСемантическая разметка для screen readers

Часто задаваемые вопросы

Чем StatelessWidget отличается от StatefulWidget?

StatelessWidget не имеет внутреннего состояния — все данные передаются через конструктор и не меняются. StatefulWidget хранит изменяемое состояние в отдельном объекте State, который переживает ребилды. Изменение состояния вызывает setState(), и Flutter перестраивает UI. Для неизменяемых элементов используйте StatelessWidget; для интерактивных — StatefulWidget.

Что такое BuildContext во Flutter?

BuildContext — дескриптор позиции виджета в Element Tree, передаваемый в метод build(). Через context виджет получает доступ к MediaQuery, Theme, Navigator, ScaffoldMessenger и InheritedWidget. BuildContext не должен сохраняться после завершения build(). Для доступа к данным используйте Builder-виджет или InheritedWidget.

Нужно ли знать Dart для работы с Flutter?

Да, Flutter использует Dart как единственный язык программирования. Dart — статически типизированный язык с null-safety, звуковыми типами (sound null safety), extension methods и pattern matching. Для начала достаточно основ Dart: классы, функции, async/await, коллекции. Dart компилируется в нативный код (AOT) через Dart Native и в JavaScript (для веба) через Dart2JS.

Flutter — это только для мобильных платформ?

Нет, Flutter поддерживает шесть платформ: iOS, Android, Web, macOS, Windows, Linux. Более 90% кода общее для всех платформ. Платформенные адаптации (камера, файловая система) реализуются через плагины или platform channels. Для десктопа Flutter использует оконную оболочку Flutter Desktop, для веба — движок CanvasKit (WebGL) или HTML-рендерер.

Как Flutter обеспечивает производительность 60 FPS?

Flutter достигает 60/120 FPS за счёт: собственного 2D-движка (Skia/Impeller), отсутствия нативного bridge (в отличие от React Native), трёх деревьев (Widget → Element → Render) с переиспользованием Element при неизменном типе/key, layout-алгоритма с однонаправленным проходом (constraints down, sizes up) и RepaintBoundary для изоляции перерисовки отдельных зон экрана.

Итоги

  • Flutter Widgets — все элементы UI: от Scaffold до SizedBox; Flutter рисует их сам на Skia/Impeller, не используя нативные компоненты.
  • StatelessWidget — виджет без состояния; build() возвращает UI на основе неизменяемых параметров конструктора.
  • StatefulWidget — виджет с изменяемым состоянием в State; setState() вызывает ребилд UI.
  • Три дерева Flutter: Widget (конфигурация) → Element (позиция) → Render (layout + paint); Element переиспользуется для производительности.
  • BuildContext — позиция виджета в дереве; доступ к MediaQuery, Theme, Navigator, InheritedWidget.
  • Material и Cupertino — два набора виджетов для Google Material Design 3 и Apple HIG соответственно.
  • Key (ValueKey, ObjectKey, UniqueKey) — идентификация виджета при изменении порядка/количества в списке.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также