Программирование с ИИ
ENRU
11.3

Виджеты

дерево, композиция и почему отступ — это тоже виджет

Что это

Во Flutter всё — виджет. Кнопка, текст, отступ, выравнивание, даже сам экран. Интерфейс собирается не из свойств, как в CSS, а из вложенных друг в друга виджетов.

Это главное отличие от всего, что было в книге раньше, и главный источник недоумения при чтении: код выглядит как глубокая лестница скобок.

Как выглядит в коде

Scaffold(
  appBar: AppBar(title: const Text('Погода')),
  body: Padding(
    padding: const EdgeInsets.all(16),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(city.name, style: Theme.of(context).textTheme.titleLarge),
        const SizedBox(height: 8),
        Text(city.temp == null ? 'нет данных' : '${city.temp}°'),
        const Spacer(),
        ElevatedButton(
          onPressed: () => onRemove(city.name),
          child: const Text('Удалить'),
        ),
      ],
    ),
  ),
)
Схема из книги — будет перерисована для сайта
То же самое деревом. Отступ и промежуток — такие же узлы, как текст и кнопка.

Как это читать

Читай по вложенности, а не по строкам. Отступы в коде повторяют структуру дерева, поэтому самое полезное при чтении — смотреть на уровень отступа.

child — один ребёнок, children — список. По этим двум словам восстанавливается вся структура: где ветвление, где цепочка.

Отступы и промежутки — тоже виджеты. В этом главное отличие от CSS:

НужноВиджет
отступ вокругPadding
промежуток междуSizedBox(height: 8)
занять всё свободноеExpanded, Spacer
выровнятьAlign, Center
в столбец / в рядColumn, Row
поверх друг другаStack

Поэтому дерево такое глубокое: то, что в CSS было бы двумя строками свойств, здесь — два уровня вложенности.

const перед виджетом. Не формальность: такой виджет создаётся один раз и не пересоздаётся при перерисовке. ИИ его часто пропускает, анализатор на это ругается.

Theme.of(context) — взять значение из темы приложения: цвет, шрифт, размер. Это аналог CSS-переменных (статья 8.3): лучше, чем вписывать размеры числами.

Row, Column и переполнение

Самая частая визуальная поломка во Flutter: содержимое не помещается, и на экране появляется жёлто-чёрная полоса с надписью о переполнении.

Причина почти всегда одна: в Row положили текст, который длиннее экрана. Лечится оборачиванием в Expanded или Flexible — они говорят «занимай место, которое есть, и не больше».

Как сказать ИИ

Запрос
Объясни это дерево виджетов: что за что отвечает.
По строке на уровень вложенности, без кода.
Запрос
Вынеси содержимое Column в отдельный виджет CityInfo
в lib/widgets/. Параметры передай через конструктор.
Поведение не меняй.
Запрос
При длинном названии города в этом Row случается overflow.
Исправь через Expanded, и объясни, почему именно так,
а не фиксированной шириной.

На что смотреть

Дерево на десять уровней в одном файле. Разбивается на виджеты.

Нет const там, где виджет не зависит от данных. Лишние пересоздания при каждой перерисовке.

Размеры числами вместо темы. fontSize: 17 вместо Theme.of(context) — те же магические числа, что в статье 8.3.

Container ради одной вещи. Если нужен только отступ — Padding, только выравнивание — Align. Container умеет всё сразу и потому прячет намерение.

Логика внутри build. Запросы к сети и вычисления в методе построения: он вызывается при каждой перерисовке, то есть часто.

Фиксированные размеры под один экран. Телефоны разные; MediaQuery и Expanded существуют именно для этого.

Шпаргалка

  • Во Flutter всё виджет, включая отступы и промежутки.

  • child — один, children — список; по ним восстанавливается дерево.

  • Читай по вложенности, а не по строкам.

  • const перед виджетом экономит пересоздание при перерисовке.

  • Размеры и цвета — из темы, а не числами.

  • Жёлто-чёрная полоса — переполнение; лечится Expanded.