Что такое виджеты в Flutter?

«Что такое виджеты в Flutter?» — вопрос из категории Flutter виджеты, который задают на 36% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Виджеты (Widgets) — это фундаментальные, иммутабельные строительные блоки пользовательского интерфейса во Flutter. Всё в UI является виджетом: от структурных элементов (столбцов, строк) до визуальных компонентов (текст, кнопки) и даже тем, отступов.

Основные концепции:

  1. Декларативный подход: Вы описываете, как UI должен выглядеть при текущем состоянии, а фреймворк сам эффективно обновляет экран.
  2. Композиция: Сложные интерфейсы создаются путем вложения простых виджетов друг в друга.
  3. Иммутабельность: Виджеты не изменяются после создания. При изменении состояния или конфигурации создается новый дерево виджетов, а Flutter Framework интеллектуально обновляет только те части экрана, которые действительно изменились.

Два основных типа виджетов:

  • StatelessWidget: Описывает часть UI, которая зависит только от своей собственной конфигурации (переданных в конструктор параметров). Не имеет внутреннего изменяемого состояния.
  • StatefulWidget: Состоит из двух объектов: самого (иммутабельного) виджета и связанного с ним объекта State, который хранит изменяемые данные и может инициировать перерисовку через вызов setState().

Пример, демонстрирующий композицию и типы:

// StatelessWidget — зависит только от переданного 'title'
class MyHeader extends StatelessWidget {
  final String title;
  const MyHeader({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    return Text(
      title,
      style: Theme.of(context).textTheme.headlineMedium,
    );
  }
}

// StatefulWidget — управляет внутренним состоянием '_counter'
class CounterButton extends StatefulWidget {
  const CounterButton({super.key});

  @override
  State<CounterButton> createState() => _CounterButtonState();
}

class _CounterButtonState extends State<CounterButton> {
  int _counter = 0;

  void _increment() {
    setState(() { // Вызов setState заставляет Flutter перестроить этот виджет
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // Композиция: кнопка содержит текст
    return ElevatedButton(
      onPressed: _increment,
      child: Text('Нажато $_counter раз'),
    );
  }
}

// Главный виджет, компонирующий другие
class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          MyHeader(title: 'Демо приложение'), // Stateless
          const SizedBox(height: 20),
          CounterButton(), // Stateful
        ],
      ),
    );
  }
}