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, реалізовані як незмінні (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 оперує трьома деревами: Widget Tree (конфігурація, створюється розробником), Element Tree (зіставлення віджета з позицією в дереві, керується фреймворком), Render Tree (об'єкти, що обчислюють layout та виконують paint). Widget створює Element, який створює RenderObject. Element перевикористовується при зміні конфігурації (rebuild) — це механізм оптимізації Flutter: якщо тип віджета та key збігаються, Element не перестворюється, а оновлюється нова конфігурація. Розуміння трьох дерев — ключ до оптимізації продуктивності Flutter-додатків.
StatelessWidget — віджет, який не зберігає внутрішній стан. Він приймає параметри через конструктор і відображає їх без можливості зміни після збірки. StatelessWidget ідеально підходить для статичних елементів: заголовків, іконок, аватарів, списків із фіксованими даними. Метод build() викликається один раз при створенні та при зміні батьківського віджета. Оскільки StatelessWidget не має стану, він не потребує окремого State-об'єкта — build() визначений прямо в класі віджета.
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 — віджет із змінним станом, який зберігається в окремому об'єкті State. Сам StatefulWidget — незмінний (immutable), як і StatelessWidget. Змінна частина винесена в State: State — об'єкт, який створюється один раз і переживає множинні ребілди віджета. Коли стан змінюється (setState()), Flutter викликає build() State, оновлюючи UI. StatefulWidget використовується для інтерактивних елементів: лічильники, текстові поля, чекбокси, анімації, таймери.
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 Tree — ієрархічна структура віджетів, що описує UI додатка. Flutter перетворює Widget Tree в Element Tree: кожен Widget створює Element, який відстежує позицію в дереві та зв'язок з RenderObject. Render Tree виконує layout (визначення розмірів та позицій) та paint (відображення). Element — ключовий оптимізаційний шар: якщо тип віджета та key не змінилися при rebuild, Element перевикористовується, оновлюючи конфігурацію без перестворення RenderObject. Це забезпечує продуктивність Flutter при високій частоті кадрів (60/120 FPS).
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 віджети')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.flutter_dash, size: 80),
const SizedBox(height: 16),
const Text(
'Привіт, 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 — дескриптор позиції віджета в 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 — опціональний параметр конструктора кожного віджета (super.key). Key допомагає Flutter ідентифікувати віджет при зміні порядку/кількості елементів у списку. Без key Flutter порівнює віджети за типом та позицією; при додаванні елемента в середину списку без key Flutter перевикористовує Element для неправильного віджета, викликаючи баги зі станом (StatefulWidget) та анімацією. Використовуйте ValueKey (унікальний ідентифікатор) для списків, ObjectKey (на основі об'єкта даних), UniqueKey (гарантовано унікальний при кожному rebuild — для форсованого перестворення).
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 для декорування.
| Категорія | Ключові віджети | Призначення |
|---|---|---|
| Layout | Row, Column, Stack, Container, Expanded, Flexible | Позиціонування та розміри дочірніх елементів |
| Material | Scaffold, AppBar, Card, Drawer, FAB, TabBar | UI-компоненти Material Design 3 |
| Cupertino | CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton | iOS-стилізовані компоненти |
| Painting | Opacity, ClipRect, Transform, DecoratedBox, BackdropFilter | Візуальні ефекти та кліпінг |
| Async | FutureBuilder, StreamBuilder | Асинхронне завантаження даних з UI-станами |
| Accessibility | Semantics, MergeSemantics | Семантична розмітка для screen readers |
Часті запитання
StatelessWidget не має внутрішнього стану — всі дані передаються через конструктор і не змінюються. StatefulWidget зберігає змінний стан в окремому об'єкті State, який переживає ребілди. Зміна стану викликає setState(), і Flutter перебудовує UI. Для незмінних елементів використовуйте StatelessWidget; для інтерактивних — StatefulWidget.
BuildContext — дескриптор позиції віджета в Element Tree, що передається в метод build(). Через context віджет отримує доступ до MediaQuery, Theme, Navigator, ScaffoldMessenger та InheritedWidget. BuildContext не повинен зберігатися після завершення build(). Для доступу до даних використовуйте Builder-віджет або InheritedWidget.
Так, Flutter використовує Dart як єдину мову програмування. Dart — статично типізована мова з null-safety, звуковими типами (sound null safety), extension methods та pattern matching. Для початку достатньо основ Dart: класи, функції, async/await, колекції. Dart компілюється в нативний код (AOT) через Dart Native та в JavaScript (для вебу) через Dart2JS.
Ні, Flutter підтримує шість платформ: iOS, Android, Web, macOS, Windows, Linux. Більше 90% коду спільне для всіх платформ. Платформені адаптації (камера, файлова система) реалізуються через плагіни або platform channels. Для десктопа Flutter використовує віконну оболонку Flutter Desktop, для вебу — двигун CanvasKit (WebGL) або HTML-рендерер.
Flutter досягає 60/120 FPS за рахунок: власного 2D-двигуна (Skia/Impeller), відсутності нативного bridge (на відміну від React Native), трьох дерев (Widget → Element → Render) з перевикористанням Element при незмінному типі/key, layout-алгоритму з однонаправленим проходом (constraints down, sizes up) та RepaintBoundary для ізоляції перемальовування окремих зон екрана.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також