Что такое виджеты в 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
        ],
      ),
    );
  }
}

Ответ 18+ 🔞

Э, слушай, давай разберёмся с этими вашими виджетами во Flutter, а то народ путается, как будто в первый раз слышит. Представь, что ты строишь интерфейс из кубиков Лего, только цифровых. Вот эти кубики — и есть виджеты. Всё, что ты видишь на экране: текст, кнопка, картинка, даже пустое место — это ёпта виджет. Овердохуища их там, на любой вкус.

Главная фишка в том, что ты не лезешь вручную и не говоришь: «Эй, кнопка, измени цвет!». Ты просто описываешь, как вся эта сбруя должна выглядеть прямо сейчас. А движок Flutter, хитрая жопа, сам соображает, что поменялось с прошлого раза, и перерисовывает только нужные куски. Эффективно, чёрт возьми. Это называется декларативный подход — ты не командуешь, а заявляешь.

А собирается всё это добро через композицию. То есть ты берешь простые виджеты и вкладываешь их друг в друга, как матрёшку, пока не получится целый экран. Ебать копать, даже тема приложения или отступ — это тоже виджеты, просто невидимые.

Теперь, внимание, блядь, самое важное разделение. Виджеты бывают двух сортов, как люди: спокойные и нервные.

  1. StatelessWidget — это как монах-отшельник. Создали его один раз, передали какие-то параметры (например, заголовок текста), и всё. У него внутри нет своего изменяемого состояния. Он посмотрел на переданные данные и отрисовался. Хоть сто раз его перестраивай — он будет одинаковым, пока ему не скормят новые параметры. Доверия ебать ноль к его самостоятельности, но зато надёжный.

  2. StatefulWidget — вот это уже персонаж с характером. Он состоит из двух половинок. Первая — сам виджет, такой же иммутабельный кореш. А вторая — объект State, это его личный дневник и бардак в одной комнате. Там хранятся изменяемые данные (например, счётчик нажатий). Когда данные меняются, этот State кричит setState() — и Flutter понимает, что пора перерисовать эту часть интерфейса заново, с новыми данными. Без этого вызова — нихуя не изменится, хоть обосрись.

Смотри на примере, тут всё станет понятнее. Вот тебе Stateless — заголовок, который просто показывает то, что ему дали:

class MyHeader extends StatelessWidget {
  final String title; // Параметр, который ему передали. Final — менять низя.
  const MyHeader({super.key, required this.title});

  @override
  Widget build(BuildContext context) {
    return Text( // Возвращает виджет Text
      title, // с переданным заголовком
      style: Theme.of(context).textTheme.headlineMedium,
    );
  }
}

А вот его нервный братан Stateful — кнопка-счётчик:

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

  @override
  State<CounterButton> createState() => _CounterButtonState(); // Создаёт свой State
}

class _CounterButtonState extends State<CounterButton> {
  int _counter = 0; // Вот оно, состояние! Менять можно.

  void _increment() {
    setState(() { // КРИЧИМ движку: "Бля, состояние поменялось, перерисуй меня!"
      _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
        ],
      ),
    );
  }
}

Вот и вся магия. Сначала терпения ноль ебать кажется, что много буков, но потом втягиваешься. Главное — понять эту разницу между Stateless и Stateful и что setState() — это волшебный пендель для перерисовки. Всё остальное — просто комбинирование этих кубиков. Пизда рулю, когда осознаёшь.