Ответ
В Flutter есть две фундаментальные категории виджетов, основанные на управлении состоянием, и несколько важных специализированных типов.
1. По управлению состоянием
-
StatelessWidget: Неизменяемый виджет. Он конфигурируется один раз при создании и не меняется в течение жизненного цикла. Используется для статического или вычисляемого на основе входных параметров (finalсвойств) контента.class GreetingText extends StatelessWidget { final String name; // Конфигурация через конструктор const GreetingText({super.key, required this.name}); @override Widget build(BuildContext context) { // Виджет перестраивается, только если изменились `key` или `name` return Text('Привет, $name!'); } } -
StatefulWidget: Виджет, который может меняться в ответ на пользовательский ввод или другие события. Он состоит из двух классов:- Сам
StatefulWidget(неизменяемый, какStatelessWidget). -
Объект
State, который сохраняет mutable-состояние и содержит методbuild.class CounterWidget extends StatefulWidget { const CounterWidget({super.key}); @override State<CounterWidget> createState() => _CounterWidgetState(); }
class _CounterWidgetState extends State
{ int _count = 0; // Изменяемое состояние void _increment() { setState(() { // Вызов setState перестраивает виджет _count++; }); }
@override Widget build(BuildContext context) { return ElevatedButton( onPressed: _increment, child: Text('Нажато $_count раз'), ); } }
- Сам
2. Специализированные виджеты
InheritedWidget: Эффективный механизм для передачи данных вниз по дереву виджетов без явной их передаче через конструкторы каждого виджета. Основа дляProvider,Theme,MediaQuery.RenderObjectWidget: Низкоуровневый виджет, который создает/обновляетRenderObject— объект, отвечающий за вычисление layout и отрисовку.SingleChildRenderObjectWidget(например,Padding) иMultiChildRenderObjectWidget(например,Row) — его потомки.StatefulBuilder&LayoutBuilder: Виджеты для создания локального состояния или реагирования на изменения constraints родителя непосредственно в методеbuild.
Ответ 18+ 🔞
Ну вот, сидишь ты, такой весь из себя, начинаешь ковыряться во Flutter, а там, ёпта, целый зоопарк этих виджетов. И главное — все друг на друга похожи, а работают по-разному, как будто специально, чтобы голова взорвалась. Давай разберёмся без этой официальной зауми, на пальцах.
Первое и главное деление — по тому, как они с состоянием дружат. Тут всё просто, как два пальца.
Первый тип — StatelessWidget. Это как памятник, только из кода. Создали его один раз, впихнули в него какие-то финальные настройки (ну там, final String name), и всё — он застыл в вечности. Сам по себе он меняться не может. Хочешь что-то другое показать — придётся выкинуть этот виджет и создать новый с другими параметрами. Внутри у него только один метод build, который рисует виджет на основе этих самых финальных пропсов. Если name поменялось — фреймворк видит это, старый виджет на свалку, новый строит. Проще некуда.
class GreetingText extends StatelessWidget {
final String name; // Вот эта штука — раз и навсегда. Приехали.
const GreetingText({super.key, required this.name});
@override
Widget build(BuildContext context) {
// Строится заново, только если `key` или `name` поменялись. Иначе — сидит, не дергается.
return Text('Привет, $name!');
}
}
Второй тип — StatefulWidget. А вот это уже хитрая жопа. Сам по себе виджет (CounterWidget) — такой же неизменяемый памятник. Но! У него есть личный раб — объект класса State. Вот этот State — он живой, в нём и хранится всё изменяемое состояние (например, счётчик _count). И когда нужно что-то поменять (пользователь кнопку тыкнул), ты вызываешь волшебный метод setState(). Он такой: «Э, бошка думай! Данные поменялись, надо перерисоваться!» — и заставляет метод build в State выполниться заново, уже с новыми цифрами.
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState(); // Родил себе state-объект
}
class _CounterWidgetState extends State<CounterWidget> {
int _count = 0; // А вот тут уже можно хранить меняющуюся хуйню
void _increment() {
setState(() { // Кричим фреймворку: «Ёбааать, всё поменялось, перерисуй нас!»
_count++;
});
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _increment,
child: Text('Нажато $_count раз'), // И тут уже актуальная цифра
);
}
}
Вот и вся магия. Stateless — тупой и быстрый, Stateful — умный, но с прицепом в виде отдельного объекта.
А теперь про специалистов, без которых никуда.
-
InheritedWidget— это вообще гениальная вещь, ебушки-воробушки. Представь, тебе нужно передать данные (скажем, настройки темы) через десять уровней виджетов вглубь. Тащить их через конструкторы каждого — это пиздец, терпения ноль ебать. ВотInheritedWidgetи решает эту проблему. Он вешается куда-то высоко в дереве, а любой его потомок внизу может достучаться до этих данных, безо всяких прямых передач. На нём, кстати, пол-экосистемы Flutter построено (Provider,Theme). -
RenderObjectWidget— это уже для самых отчаянных, низкоуровневая жесть. Когда обычные виджеты тебе не хватает и нужно лезть в самые дебри: управлять тем, как именно твой виджет рассчитывает свои размеры (layout) и рисуется на экране (paint).PaddingилиRow— они как раз внутри используют такие штуки. Без реальной необходимости туда лучше не совать нос, а то сам от себя охуеешь. -
StatefulBuilderиLayoutBuilder— это такие хитрые костыли, но очень полезные. Допустим, тебе нужно немного изменяемого состояния прямо внутри методаbuildбольшого виджета, не плодя отдельныйStatefulWidgetна ровном месте — вот тебеStatefulBuilder. Или нужно сделать виджет, который реагирует на изменения размеров, которые ему выделил родитель (ну там, если экран широкий — раскладка одна, узкий — другая) — этоLayoutBuilder. Удобные пацаны для специфичных задач.
Короче, вся система на этом стоит. Сначала пойми разницу между Stateless и Stateful — это основа основ. А потом уже, по мере надобности, начинай ковырять этих спецов. Главное — не пытайся всё выучить сразу, а то будет овердохуища информации, и ты просто накроешься медным тазом.