1. Що таке Flutter?
Flutter - це open-source UI toolkit від Google для створення кросплатформених застосунків з єдиної кодової бази.
-
Кросплатформеність: Дозволяє створювати застосунки для iOS, Android, Web, Windows, macOS і Linux.
-
Власний рушій рендерингу: Flutter малює інтерфейс самостійно, а не використовує нативні OEM-віджети як основу UI.
-
Віджетний підхід: У Flutter майже все є віджетами: екран, текст, відступи, кнопки, анімації.
-
Висока швидкість розробки: Hot Reload дозволяє швидко бачити зміни в коді без повного перезапуску застосунку.
-
Єдина мова розробки: Увесь клієнтський код зазвичай пишеться на Dart.
Flutter часто використовують для швидкої розробки MVP, продуктових мобільних застосунків і внутрішніх корпоративних систем.
2. Чому Flutter часто обирають для мобільної розробки?
Flutter часто обирають через баланс між швидкістю розробки, якістю UI та можливістю підтримувати одну кодову базу для кількох платформ.
-
Одна кодова база: Менше дублювання логіки між Android та iOS.
-
Швидка розробка: Hot Reload пришвидшує ітерації команди.
-
Передбачуваний UI: Flutter рендерить інтерфейс сам, тому дизайн виглядає більш консистентно між платформами.
-
Хороша продуктивність: Для більшості бізнес-застосунків Flutter дає продуктивність, достатню для production-рівня.
-
Сильна екосистема: Є велика кількість пакетів для навігації, стану, HTTP, локального зберігання, аналітики та тестування.
-
Зручна робота з кастомним UI: Якщо в продукті багато нестандартних екранів, анімацій або складної дизайн-системи, Flutter часто виграє у швидкості реалізації.
- Коли треба швидко вийти на iOS та Android.
- Коли команда невелика і важливо скоротити витрати на підтримку.
- Коли в продукті багато кастомного інтерфейсу.
3. Які платформи підтримує Flutter?
Flutter підтримує кілька платформ з однієї кодової бази.
- Android
- iOS
- Web
- Windows
- macOS
- Linux
- Flutter також використовується для embedded-рішень та спеціалізованих пристроїв, якщо є відповідна інтеграція з рушієм.
- Найчастіше у комерційній розробці Flutter застосовують саме для мобільних платформ, але web і desktop теж підтримуються офіційно.
4. Що таке Dart і чому Flutter використовує саме цю мову?
Dart - це мова програмування, розроблена Google. Flutter використовує Dart як основну мову для написання UI, бізнес-логіки та взаємодії з фреймворком.
-
Швидка компіляція під час розробки: Це робить можливим Hot Reload.
-
AOT і JIT: Dart підтримує JIT для швидкої розробки та AOT-компіляцію для ефективного production-білду.
-
Простий синтаксис: Dart легко сприймається розробниками з досвідом у Java, JavaScript, C#, Kotlin або Swift.
-
Хороша підтримка асинхронності:
Future,Stream,async/awaitприродно підходять для клієнтської розробки. -
Сильна типізація: Це покращує підтримуваність, рефакторинг і стабільність великих проєктів.
Для Flutter потрібна мова, яка добре працює і в режимі швидкої розробки, і в режимі оптимізованої компіляції. Dart закриває обидва сценарії.
5. Яка структура проєкту Flutter?
Типовий Flutter-проєкт має кілька стандартних директорій і службових файлів.
lib/- основний код застосунку.test/- unit- та widget-тести.android/- нативна Android-частина проєкту.ios/- нативна iOS-частина проєкту.web/- конфігурація та точка входу для web.macos/,windows/,linux/- desktop-платформи.pubspec.yaml- залежності, ресурси, метадані проєкту.
- У більшості випадків основна продуктова логіка живе в
lib/. - Платформені папки змінюють тоді, коли потрібні нативні налаштування, permissions, SDK-конфігурація або platform channels.
lib/
core/
features/
shared/
app/
main.dart
У production-проєктах зазвичай важливо не лише знати стандартну структуру Flutter, а й мати зрозумілу feature-based або layered-архітектуру.
6. Що таке файл `pubspec.yaml` і для чого він використовується?
pubspec.yaml - це головний конфігураційний файл Dart/Flutter-проєкту.
-
Керування залежностями: Пакети, які використовує застосунок.
-
Опис ресурсів: Підключення assets, шрифтів, іконок.
-
Метадані проєкту: Назва, версія, опис, environment constraints.
-
Налаштування dev-залежностей: Наприклад,
flutter_test,build_runner,flutter_lints.
name: flutter_interview_questions
description: Flutter interview questions and answers
version: 1.0.0+1
environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
dio: ^5.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
flutter:
uses-material-design: true
assets:
- assets/images/Після зміни pubspec.yaml зазвичай виконують flutter pub get, щоб підтягнути
нові залежності.
7. Яка роль функції `main()` у Flutter?
main() - це точка входу в Flutter-застосунок, з якої починається виконання
програми.
-
Запуск застосунку: Саме в
main()зазвичай викликаютьrunApp(). -
Первинна ініціалізація: Тут можна ініціалізувати сервіси, DI-контейнер, Firebase, локальне сховище або конфігурацію середовища.
-
Налаштування до старту UI: Якщо перед запуском потрібен
await,main()можна зробитиasync.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// await someAsyncInitialization();
runApp(const MyApp());
}8. Що робить функція `runApp()`?
runApp() запускає Flutter-застосунок і монтує переданий кореневий віджет у
дерево віджетів.
-
Створюється кореневий вузол UI: Саме з нього починається все дерево віджетів.
-
Flutter починає процес побудови інтерфейсу: Далі фреймворк викликає
build()і рендерить екран. -
Застосунок переходить під керування Flutter framework: Всі наступні оновлення UI обробляються через систему віджетів, елементів і render objects.
void main() {
runApp(const MyApp());
}- Зазвичай у
runApp()передаютьMaterialApp,CupertinoAppабо власний кореневийApp-віджет. - Повторний виклик
runApp()можливий, але в типовому життєвому циклі застосунку він зазвичай викликається один раз.
9. Що таке віджети (widgets) у Flutter?
Віджети - це базові будівельні блоки UI у Flutter. Вони описують, як має виглядати частина інтерфейсу і як вона повинна поводитися.
- Текст:
Text - Кнопка:
ElevatedButton - Відступ:
Padding - Розмітка:
Column,Row,Stack - Екран:
Scaffold
-
Декларативність: Ви описуєте UI як набір віджетів.
-
Композиція: Складний інтерфейс збирається з простих віджетів.
-
Імм'ютабельність: Віджети самі по собі незмінні; зміни UI досягаються через перебудову дерева.
class HelloText extends StatelessWidget {
const HelloText({super.key});
@override
Widget build(BuildContext context) {
return const Text('Hello Flutter');
}
}10. У чому різниця між `StatelessWidget` і `StatefulWidget`?
Різниця полягає в тому, чи має віджет внутрішній змінний стан, який впливає на його відображення.
Використовується для UI, який залежить лише від вхідних параметрів і не має власного змінного стану.
class TitleText extends StatelessWidget {
final String title;
const TitleText({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Text(title);
}
}Використовується тоді, коли віджет має стан, який може змінюватися протягом життєвого циклу.
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $counter'),
ElevatedButton(
onPressed: () {
setState(() {
counter++;
});
},
child: const Text('Increment'),
),
],
);
}
}-
Стан:
StatelessWidgetне має mutable state,StatefulWidgetмає. -
Оновлення UI: У
StatefulWidgetUI оновлюється черезsetState()або інші state management підходи. -
Сценарії використання: Статичні елементи UI проти інтерактивних або динамічних частин екрана.
11. Що таке дерево віджетів (widget tree)?
Дерево віджетів - це ієрархія всіх віджетів, з яких складається інтерфейс Flutter-застосунку.
-
Кожен віджет може містити дочірні віджети.
-
Весь екран формується як дерево вкладених елементів.
-
Під час змін стану Flutter перебудовує частини цього дерева.
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: const Center(
child: Text('Hello'),
),
),
)У цьому прикладі MaterialApp є коренем, всередині нього знаходиться
Scaffold, далі AppBar, Center і Text.
- Розуміння widget tree допомагає правильно будувати UI.
- Це критично для дебагу, оптимізації rebuild-ів і роботи з контекстом.
12. Що таке `BuildContext`?
BuildContext - це посилання на місце віджета в дереві віджетів.
-
Доступ до батьківських залежностей: Наприклад,
Theme,MediaQuery,Navigator,ScaffoldMessenger,Provider. -
Навігація: Через
Navigator.of(context). -
Отримання локальних налаштувань середовища: Розмір екрана, тема, локаль та інші inherited dependencies.
final theme = Theme.of(context);
final size = MediaQuery.of(context).size;BuildContext повинен належати правильному місцю в дереві. Наприклад, якщо
викликати ScaffoldMessenger.of(context) занадто рано або з контексту, який не
має потрібного предка, отримаєте помилку.
Контекст треба сприймати не як "глобальний доступ", а як "позицію віджета в дереві на цей момент".
13. Що таке `Key` у Flutter і для чого він потрібен?
Key - це механізм ідентифікації віджетів у дереві, який допомагає Flutter
правильно зіставляти старі та нові віджети під час rebuild.
-
Збереження стану при зміні порядку елементів.
-
Коректна робота списків і динамічних колекцій.
-
Доступ до віджетів у тестах.
-
Керування унікальністю елементів у дереві.
ListView(
children: const [
ListTile(key: ValueKey('user_1'), title: Text('User 1')),
ListTile(key: ValueKey('user_2'), title: Text('User 2')),
],
)ValueKey- коли є стабільне значення-ідентифікатор.ObjectKey- коли ключ базується на об'єкті.UniqueKey- коли потрібна гарантована унікальність.GlobalKey- для доступу до state або context конкретного віджета.
GlobalKey треба використовувати обережно. Це потужний, але відносно дорогий
інструмент, який не варто застосовувати без реальної потреби.
14. Що таке Hot Reload і Hot Restart?
Hot Reload і Hot Restart - це два механізми швидкого перезапуску застосунку під час розробки.
- Впроваджує зміни в коді майже миттєво.
- Зберігає поточний стан застосунку.
- Найкраще підходить для змін у UI, стилях, логіці
build().
- Перезапускає Dart isolate.
- Скидає поточний стан застосунку.
- Повторно виконує
main(). - Потрібен, коли Hot Reload вже недостатній.
| Критерій | Hot Reload | Hot Restart |
|---|---|---|
| Швидкість | Швидше | Повільніше |
| Збереження стану | Так | Ні |
Виклик main() |
Ні | Так |
| Типові сценарії | Зміни UI та дрібної логіки | Зміни ініціалізації або глобального стану |
Не всі зміни можна коректно застосувати через Hot Reload. Наприклад, зміни в initialization flow або деяких static-конструкціях можуть вимагати Hot Restart.
15. Які режими збірки існують у Flutter (Debug, Profile, Release)?
У Flutter є три основні режими збірки, кожен з яких має своє призначення.
- Використовується під час розробки.
- Підтримує Hot Reload.
- Має додаткові перевірки, assertions і dev tooling.
- Не підходить для оцінки реальної продуктивності.
- Використовується для аналізу продуктивності.
- Ближчий до production-поведінки.
- Дає змогу використовувати профілювання CPU, GPU, memory та frame rendering.
- Використовується для production.
- Максимально оптимізований.
- Без debug-інструментів, assertions і dev overhead.
- Debug - щоденна розробка.
- Profile - performance tuning.
- Release - реліз у store або production distribution.
16. Що таке `MaterialApp`?
MaterialApp - це кореневий віджет для застосунків, які використовують
Material Design.
- Навігацію
- Тему застосунку
- Локалізацію
- Маршрути
- Базову Material-конфігурацію
import 'package:flutter/material.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
home: const HomePage(),
);
}
}У більшості Flutter-застосунків MaterialApp є точкою входу у верхньому рівні
дерева віджетів.
17. Що таке віджет `Scaffold`?
Scaffold - це базовий layout-віджет для Material Design екранів.
appBar- верхня панель.body- основний контент екрана.floatingActionButton- плаваюча action-кнопка.drawer- бокове меню.bottomNavigationBar- нижня навігація.snackBar/bottomSheetintegration - взаємодія з Material shell.
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: const Center(
child: Text('Content'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
);
}
}Scaffold дає стандартний "каркас" екрана. Без нього багато Material-поведінок
доведеться організовувати вручну.
18. Для чого використовується `SafeArea`?
SafeArea використовується для того, щоб контент не потрапляв під системні
елементи інтерфейсу.
- Статус-бар
- Notch / Dynamic Island / вирізи екрана
- Системні жести і нижні safe insets
- Інші системні області, які не варто перекривати контентом
SafeArea(
child: Column(
children: const [
Text('Header'),
Text('Body'),
],
),
)- На екранах із кастомним layout.
- Коли контент прилягає до країв екрана.
- Коли треба швидко забезпечити базову безпеку розміщення UI.
SafeArea не замінює продуманий layout, але допомагає уникнути типових проблем
з перекриттям системними зонами.
19. Що таке мова програмування Dart?
Dart - це сучасна об'єктно-орієнтована мова програмування, розроблена Google, яка використовується як основна мова для Flutter-розробки.
-
Сильна типізація: Dart підтримує статичну типізацію, що покращує передбачуваність і безпеку коду.
-
JIT і AOT-компіляція: Це дозволяє поєднати швидку розробку та продуктивний production build.
-
Підтримка асинхронності:
Future,Stream,async/awaitє вбудованими частинами мови. -
Зручний синтаксис: Dart відносно легко вивчати розробникам із досвідом у Java, Kotlin, Swift, C# або JavaScript.
-
Sound null safety: Мова допомагає зменшити кількість null-related помилок ще на етапі компіляції.
Dart не просто "мова поруч із Flutter", а фундаментальна частина екосистеми. Весь UI, бізнес-логіка, стан, асинхронність і тести у Flutter зазвичай пишуться саме на Dart.
20. Чим відрізняються позиційні та іменовані параметри у Dart?
У Dart параметри функцій можуть бути позиційними або іменованими.
Передаються за порядком.
void printUser(String name, int age) {
print('$name is $age years old');
}
printUser('Anna', 25);Передаються за назвою, тому виклик стає більш читабельним.
void printUser({required String name, required int age}) {
print('$name is $age years old');
}
printUser(name: 'Anna', age: 25);-
Читабельність: Іменовані параметри краще підходять для API з великою кількістю аргументів.
-
Порядок передачі: Для позиційних важливий порядок, для іменованих - ні.
-
Гнучкість: Іменовані параметри часто краще масштабуються, коли параметрів стає більше.
У Flutter більшість конструкторів віджетів активно використовують саме іменовані параметри, бо це суттєво покращує читабельність UI-коду.
21. У чому різниця між `var`, `final` і `const`?
var, final і const у Dart використовуються для оголошення змінних, але
мають різну семантику.
Тип виводиться автоматично, а значення можна змінювати.
var name = 'Flutter';
name = 'Dart';Змінна може бути присвоєна лише один раз, але її значення може бути відоме лише під час виконання.
final currentTime = DateTime.now();Значення має бути відомим на етапі компіляції.
const pi = 3.14159;
const appName = 'Flutter App';var- звичайна змінна.final- одноразове присвоєння під час runtime.const- compile-time константа.
У Flutter бажано використовувати const там, де це можливо, особливо для
віджетів, тому що це може зменшити кількість зайвих об'єктів і rebuild overhead.
22. Що таке null-aware оператори?
Null-aware оператори в Dart - це спеціальні оператори для безпечної роботи з
null.
?.- виклик методу або доступ до властивості лише якщо об'єкт неnull.??- повертає значення справа, якщо зліваnull.??=- присвоює значення лише якщо зміннаnull.!- примусово каже компілятору, що значення неnull.
String? name;
print(name?.length);
String result = name ?? 'Guest';
name ??= 'Anonymous';String? title;
print(title!.length);Цей оператор треба використовувати обережно, тому що якщо значення буде null,
відбудеться runtime error.
Null-aware оператори роблять код коротшим, безпечнішим і прибирають потребу в
надмірних ручних перевірках на null.
23. Що таке sound null safety у Dart?
Sound null safety - це механізм у Dart, який дозволяє відокремлювати nullable та non-nullable типи і виявляти частину null-related помилок ще під час компіляції.
Якщо тип оголошений як не-nullable, то він не може містити null.
String name = 'Flutter';
String? nullableName;- Менше runtime-помилок
- Ясніший контракт типів
- Кращий рефакторинг
- Більш надійний production-код
String- значення обов'язково неnullString?- значення може бутиnull
Для великих Flutter-проєктів sound null safety суттєво зменшує кількість багів,
пов'язаних із неочікуваними null значеннями в UI, API-моделях та state
management.
24. Що таке `async` і `await`?
async і await у Dart використовуються для зручної роботи з асинхронним
кодом.
Позначає, що функція виконує асинхронну роботу і зазвичай повертає Future.
Дозволяє дочекатися результату асинхронної операції без вкладених callback-ів.
Future<void> loadUser() async {
final user = await fetchUser();
print(user);
}- Код читається як синхронний
- Менше вкладеності
- Простіша обробка помилок через
try/catch
Future<void> loadData() async {
try {
final data = await fetchData();
print(data);
} catch (e) {
print('Error: $e');
}
}25. Що таке `Future`?
Future у Dart - це об'єкт, який представляє результат асинхронної операції,
що буде доступний пізніше.
Future - це "обіцянка" отримати одне значення або помилку в майбутньому.
Future<String> fetchUserName() async {
await Future.delayed(const Duration(seconds: 1));
return 'Viktor';
}- Успішний результат
- Помилка
final name = await fetchUserName();або
fetchUserName()
.then((value) => print(value))
.catchError((error) => print(error));- HTTP-запити
- Читання файлів
- Робота з локальною базою
- Ініціалізація сервісів
- Навігація, діалоги, permission flows
26. Що таке `Stream`?
Stream - це послідовність асинхронних подій або значень, які приходять з
часом.
Якщо Future дає одне значення в майбутньому, то Stream може давати багато
значень протягом часу.
Stream<int> counterStream() async* {
for (int i = 1; i <= 3; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}await for (final value in counterStream()) {
print(value);
}- WebSocket
- Поширення стану
- Підписка на зміни в базі даних
- Події UI або системні події
Stream часто використовують у BLoC, реактивних потоках даних та в ситуаціях,
де важливі не одноразові, а постійні оновлення.
27. У чому різниця між `Future` і `Stream`?
Future і Stream обидва використовуються для асинхронності, але вирішують
різні задачі.
| Критерій | Future |
Stream |
|---|---|---|
| Кількість значень | Одне значення або помилка | Багато значень з часом |
| Завершення | Один раз | Може тривати довго або завершитися пізніше |
| Типовий сценарій | HTTP-запит, одноразове читання | WebSocket, підписка, live updates |
Future: завантажити профіль користувача один раз.Stream: слухати оновлення чату в реальному часі.
Якщо відповідь потрібна один раз - зазвичай це Future.
Якщо потрібен потік оновлень - зазвичай це Stream.
28. Що таке event loop у Dart?
Event loop у Dart - це механізм, який керує виконанням асинхронних задач у одному isolate.
- Синхронний код виконується одразу
- Асинхронні задачі ставляться в черги
- Event loop по черзі бере задачі та виконує їх
- Microtask queue - має вищий пріоритет.
- Event queue - звичайні асинхронні події.
void main() {
print('1');
Future(() => print('2'));
scheduleMicrotask(() => print('3'));
print('4');
}Результат буде:
1
4
3
2
Розуміння event loop допомагає правильно працювати з Future, Stream,
мікротасками, UI responsiveness і уникати неочікуваного порядку виконання коду.
29. Що таке mixins у Dart?
Mixins у Dart - це механізм повторного використання коду між класами без класичного множинного наслідування.
- Повторне використання поведінки
- Додавання спільної логіки кільком класам
- Композиція можливостей без жорсткої ієрархії
mixin LoggerMixin {
void log(String message) {
print('LOG: $message');
}
}
class UserService with LoggerMixin {
void loadUser() {
log('Loading user...');
}
}SingleTickerProviderStateMixinTickerProviderStateMixinAutomaticKeepAliveClientMixin
Mixins корисні, коли треба поділитися поведінкою між кількома класами, але ця поведінка не повинна бути окремим базовим класом.
30. Що таке extension methods?
Extension methods у Dart дозволяють додавати нові методи або геттери до існуючих типів без зміни їхнього вихідного коду.
extension StringX on String {
bool get isEmail => contains('@');
}Тепер можна писати:
final result = 'test@example.com'.isEmail;- Покращення читабельності
- Винесення utility-логіки ближче до типу
- Прибирання зайвих helper-класів
- Extensions для
BuildContext - Extensions для
String,DateTime,num - Extensions для теми, відступів, локалізації
Extension methods покращують API коду, але ними не варто зловживати. Якщо extension починає ховати складну бізнес-логіку, це зазвичай погіршує передбачуваність коду.
31. Що таке `typedef` у Dart?
typedef у Dart використовується для створення псевдонімів типів, найчастіше
для функцій.
typedef OnUserTap = void Function(String userId);Тепер цей тип можна використовувати так:
class UserTile {
final OnUserTap onTap;
UserTile({required this.onTap});
}- Покращує читабельність API
- Додає семантичний зміст функціональним типам
- Спрощує повторне використання однакових сигнатур
- Callbacks у віджетах
- DI і service contracts
- State management APIs
- Stream/listener contracts
32. Що таке factory constructor?
Factory constructor у Dart - це конструктор, який не обов'язково створює новий екземпляр класу щоразу при виклику.
- Може повертати кешований об'єкт
- Може повертати екземпляр підкласу
- Може містити додаткову логіку перед створенням об'єкта
class Logger {
static final Map<String, Logger> _cache = {};
final String name;
factory Logger(String name) {
return _cache.putIfAbsent(name, () => Logger._internal(name));
}
Logger._internal(this.name);
}Замість створення нового Logger щоразу factory constructor повертає вже
існуючий екземпляр для того самого name.
- Singleton-подібні сценарії
- Парсинг моделей
- Абстракції, де потрібен контроль над створенням екземпляра
Factory constructor відрізняється від звичайного тим, що не має прямого доступу
до this, бо об'єкт може ще не бути створений.
33. Як працює система layout у Flutter?
Система layout у Flutter працює за принципом constraints go down, sizes go up, parent sets position.
- Батьківський віджет передає constraints вниз
- Дочірній віджет обирає свій розмір у межах цих constraints
- Батьківський віджет визначає позицію дочірнього елемента
Flutter не використовує XML-layout систему на кшталт Android View hierarchy. Замість цього кожен віджет бере участь у чіткій моделі обчислення розміру та позиції.
- Допомагає розуміти помилки типу overflow.
- Дає можливість передбачати поведінку
Row,Column,Expanded,Flexible. - Критично для побудови адаптивних інтерфейсів.
Якщо layout "ламається", майже завжди треба дивитися на constraints, які отримує віджет від свого parent.
34. Які основні віджети використовуються для побудови макетів?
У Flutter для побудови макетів найчастіше використовуються базові layout віджети, з яких складається майже весь інтерфейс.
Row- горизонтальне розміщення елементівColumn- вертикальне розміщення елементівContainer- універсальний обгортковий віджетSizedBox- фіксований розмір або відступExpanded- зайняття доступного просторуFlexible- гнучке використання просторуStack- накладання елементів один на одинPadding- внутрішні відступиAlign/Center- вирівнюванняListView- прокручувані спискиWrap- перенесення елементів на новий рядокScaffold- базова структура екрана
У більшості екранів Flutter-розмітка будується не одним "великим layout", а комбінацією простих віджетів.
35. У чому різниця між `Row` і `Column`?
Row і Column - це базові flex-віджети у Flutter, але вони працюють у різних
напрямках.
Розміщує дочірні елементи горизонтально.
Row(
children: const [
Text('A'),
Text('B'),
Text('C'),
],
)Розміщує дочірні елементи вертикально.
Column(
children: const [
Text('A'),
Text('B'),
Text('C'),
],
)Rowпрацює по горизонтальній осіColumnпрацює по вертикальній осі
І Row, і Column можуть викликати overflow, якщо їхні дочірні елементи не
вміщаються в доступний простір.
36. Що таке `mainAxisAlignment` і `crossAxisAlignment`?
mainAxisAlignment і crossAxisAlignment - це параметри вирівнювання у flex-
віджетах, таких як Row і Column.
mainAxisAlignmentкерує вирівнюванням уздовж головної осіcrossAxisAlignmentкерує вирівнюванням уздовж поперечної осі
- Main axis = горизонтальна
- Cross axis = вертикальна
- Main axis = вертикальна
- Cross axis = горизонтальна
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Text('Left'),
Text('Right'),
],
)MainAxisAlignment.startMainAxisAlignment.centerMainAxisAlignment.endMainAxisAlignment.spaceBetweenCrossAxisAlignment.startCrossAxisAlignment.centerCrossAxisAlignment.endCrossAxisAlignment.stretch
37. Що таке віджет `Container`?
Container - це універсальний віджет-обгортка, який дозволяє задавати розмір,
відступи, вирівнювання, декорацію та інші layout-властивості.
- Задавати
widthіheight - Додавати
paddingіmargin - Застосовувати
decoration - Вирівнювати дочірній елемент
- Фарбувати фон
Container(
width: 200,
height: 100,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
),
child: const Text('Hello'),
)Container зручний, але не завжди оптимальний як "віджет на всі випадки". Якщо
потрібна лише одна проста функція, часто краще використати спеціалізований
віджет, наприклад Padding, ColoredBox, SizedBox або Align.
38. Що таке віджет `SizedBox`?
SizedBox - це віджет, який задає фіксований розмір для дочірнього елемента або
використовується як простий spacer.
- Фіксована ширина або висота
- Порожній відступ між елементами
- Обмеження розміру дочірнього віджета
const SizedBox(height: 16)або
SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {},
child: const Text('Submit'),
),
)Для простих відступів між елементами SizedBox зазвичай читабельніший і
легший, ніж Container.
39. Що таке віджет `Expanded`?
Expanded - це віджет, який змушує дочірній елемент зайняти весь доступний
вільний простір усередині Row, Column або Flex.
Expanded каже Flutter: "дай цьому елементу стільки вільного місця, скільки
можливо".
Row(
children: [
const Icon(Icons.menu),
Expanded(
child: Container(
height: 40,
color: Colors.blue,
),
),
],
)Можна використовувати flex, щоб керувати пропорціями.
Expanded(
flex: 2,
child: Container(color: Colors.red),
)Expanded працює тільки всередині Flex-based віджетів: Row, Column,
Flex.
40. Що таке віджет `Flexible`?
Flexible - це віджет для гнучкого розподілу простору всередині Row,
Column або Flex.
Expandedзмушує елемент зайняти весь доступний простір.Flexibleдозволяє елементу займати простір більш гнучко.
Row(
children: [
Flexible(
child: Text(
'Very long text that can wrap',
),
),
],
)Flexible корисний, коли елемент має адаптуватися до простору, але не
обов'язково розтягуватися максимально.
41. Що таке віджет `Spacer`?
Spacer - це спеціальний flex-віджет, який займає вільний простір між іншими
елементами.
Row(
children: const [
Text('Left'),
Spacer(),
Text('Right'),
],
)- Розштовхування елементів
- Побудова адаптивного простору в
RowабоColumn - Поліпшення читабельності коду замість ручних обчислень відступів
Spacer фактично працює як Expanded з порожнім дочірнім елементом.
42. Що таке віджет `Stack`?
Stack - це layout-віджет, який дозволяє розміщувати елементи один поверх
одного.
- Overlay-інтерфейси
- Бейджі поверх картинок
- Кнопки поверх контенту
- Складні композиції UI
Stack(
children: [
Image.network('https://example.com/image.png'),
const Positioned(
top: 8,
right: 8,
child: Icon(Icons.favorite, color: Colors.red),
),
],
)У Stack порядок дочірніх елементів має значення: пізніші елементи малюються
поверх попередніх.
43. Що таке `Positioned`?
Positioned - це віджет, який використовується всередині Stack для точного
позиціонування дочірнього елемента.
topbottomleftrightwidthheight
Stack(
children: const [
Positioned(
top: 10,
right: 10,
child: Text('Badge'),
),
],
)Positioned працює тільки як direct child всередині Stack.
44. Що таке `LayoutBuilder`?
LayoutBuilder - це віджет, який дозволяє будувати UI на основі constraints,
отриманих від батьківського віджета.
- Адаптивний layout
- Різна поведінка для вузьких і широких екранів
- Рішення, де потрібно знати доступний простір під час build
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return const Text('Tablet layout');
}
return const Text('Phone layout');
},
)LayoutBuilder особливо корисний тоді, коли рішення треба приймати не за
розміром всього екрана, а за реальним простором, доступним конкретному віджету.
45. Що таке `MediaQuery`?
MediaQuery - це механізм доступу до інформації про поточне середовище
відображення: розмір екрана, орієнтація, padding, text scale factor та інші
метрики.
- Розмір екрана
- Орієнтацію
- Safe area insets
- Налаштування масштабу тексту
final size = MediaQuery.of(context).size;
final width = size.width;MediaQuery добре підходить для screen-level адаптації, але якщо йдеться про
локальні constraints конкретного віджета, часто правильніше використовувати
LayoutBuilder.
46. Що таке `SingleChildScrollView`?
SingleChildScrollView - це scroll-віджет для одного дочірнього елемента, який
дозволяє прокручувати контент, якщо він не вміщується на екрані.
- Форми
- Невеликі екрани з вертикальним контентом
- Контент, який зазвичай поміщається, але іноді може overflow-итися
SingleChildScrollView(
child: Column(
children: const [
Text('Section 1'),
Text('Section 2'),
],
),
)Для великих списків SingleChildScrollView не підходить так добре, як
ListView, бо він рендерить весь дочірній контент одразу.
47. Що таке `ListView.builder`?
ListView.builder - це ефективний спосіб створення великих або динамічних
списків у Flutter.
На відміну від статичного ListView(children: [...]), ListView.builder
створює елементи ліниво, у міру потреби.
ListView.builder(
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
)- Краща продуктивність на великих списках
- Менше споживання пам'яті
- Зручна робота з динамічними даними
48. Що таке `AspectRatio`?
AspectRatio - це віджет, який зберігає задане співвідношення ширини до
висоти.
AspectRatio(
aspectRatio: 16 / 9,
child: Container(
color: Colors.blue,
),
)- Зображення
- Відеоплеєри
- Картки з фіксованими пропорціями
- Адаптивні UI-блоки
AspectRatio спрощує побудову елементів, які мають виглядати пропорційно на
різних екранах.
49. Що таке `Visibility`?
Visibility - це віджет, який дозволяє керувати відображенням дочірнього
елемента.
Показати або приховати елемент залежно від умови.
Visibility(
visible: isLoading,
child: const CircularProgressIndicator(),
)Visibility має додаткові параметри, які дозволяють контролювати, чи
зберігати розмір, state, animation та semantic-інформацію прихованого елемента.
Якщо потрібне просте умовне рендерення, іноді читабельніше використовувати
звичайний if або ternary-вираз. Visibility корисний тоді, коли треба тонше
керувати поведінкою прихованого віджета.
50. Що таке state у Flutter?
State у Flutter - це дані, від яких залежить те, як виглядає або поводиться UI в конкретний момент часу.
Якщо значення змінюється і через це має оновитися інтерфейс, це і є state.
- Значення лічильника
- Текст у полі вводу
- Стан завантаження
- Обраний таб
- Список отриманих з API даних
Flutter є декларативним фреймворком. Це означає, що UI описується як функція від поточного state.
Робота з Flutter значною мірою зводиться до правильної відповіді на питання: "де має жити цей state, хто ним володіє і хто повинен на нього реагувати?"
51. У чому різниця між локальним станом (ephemeral state) і станом застосунку (app state)?
Різниця між ephemeral state і app state полягає в області відповідальності та тривалості життя цих даних.
Це локальний стан конкретного віджета або невеликої частини UI.
- Поточне значення checkbox
- Стан відкриття/закриття секції
- Поточний індекс у
PageView
Це стан, який важливий для значної частини застосунку або має жити довше, ніж один окремий віджет.
- Авторизація користувача
- Тема застосунку
- Кошик в e-commerce
- Профіль користувача
| Критерій | Ephemeral state | App state |
|---|---|---|
| Область | Один віджет або малий UI-блок | Кілька екранів або весь застосунок |
| Тривалість | Коротка | Довша |
| Приклади | Animation, selection, input | Auth, cart, settings, user data |
Не варто піднімати локальний стан до глобального рівня без причини. Це лише ускладнює архітектуру.
52. Як працює `setState()`?
setState() - це метод у StatefulWidget, який повідомляє Flutter, що стан
змінився і відповідну частину UI потрібно перебудувати.
- Ви змінюєте локальний state
- Обгортаєте цю зміну в
setState() - Flutter помічає віджет як dirty
- Фреймворк викликає
build()повторно
setState(() {
counter++;
});setState() не "малює UI сам". Він лише тригерить rebuild для цього State
об'єкта.
- Простий локальний стан
- Невеликі інтерактивні елементи
- Швидкі прототипи
Якщо стан використовується в багатьох екранах або має складний життєвий цикл, краще застосувати окремий state management підхід.
53. Які підходи до керування станом використовують у Flutter?
У Flutter існує кілька популярних підходів до state management. Вибір залежить від масштабу проєкту, складності домену та вимог до підтримуваності.
setState()- для простого локального стануInheritedWidget- базовий механізм поширення залежностей у деревіProvider- простий і популярний wrapper надInheritedWidget- BLoC / Cubit - поділ UI і бізнес-логіки через потоки або state classes
- Riverpod - сучасніший підхід із кращою testability і dependency graph
- Redux - централізований state store
ValueNotifier/ChangeNotifier- lightweight реактивні моделі
- Для малого екрана достатньо
setState() - Для середніх застосунків часто підходить
Providerабо Riverpod - Для складної бізнес-логіки часто вибирають BLoC або Riverpod
Не існує "єдиного правильного" state management. Правильний вибір той, який робить код зрозумілим, прогнозованим і підтримуваним.
54. Що таке `Provider`?
Provider - це популярна бібліотека для dependency injection і state
management у Flutter, побудована поверх InheritedWidget.
- Доступ до об'єктів вище по дереву
- Оновлення UI при зміні state
- Простіший API, ніж у чистого
InheritedWidget
ChangeNotifierProvider(
create: (_) => CounterNotifier(),
child: const MyApp(),
)Потім у віджеті:
final counter = context.watch<CounterNotifier>();- Невисокий поріг входу
- Добре підходить для невеликих і середніх застосунків
- Простий для команди, яка не хоче складну реактивну архітектуру
На великих проєктах із складним dependency graph і великою кількістю станів
Provider може ставати менш зручним, ніж Riverpod або BLoC.
55. Що таке архітектура BLoC?
BLoC (Business Logic Component) - це підхід до архітектури, у якому бізнес-логіка відокремлюється від UI і взаємодіє з ним через події та стани.
- UI відправляє event
- BLoC обробляє логіку
- BLoC віддає новий state
- UI реагує на state
- Чітке розділення відповідальностей
- Прогнозований потік даних
- Хороша testability
- Зручно для складної логіки
EventStateBlocBlocBuilderBlocListener
BLoC добре підходить для середніх і великих застосунків, де важлива дисципліна архітектури, відокремлення доменної логіки та контрольований data flow.
56. Що таке Riverpod?
Riverpod - це сучасна бібліотека для state management і dependency injection у
Flutter, створена як еволюція ідей Provider.
- Кращий контроль залежностей
- Відсутність жорсткої прив'язки до
BuildContext - Кращу testability
- Безпечніший і більш декларативний API
Стан і залежності описуються через providers, а UI або сервіси підписуються на них явно.
- Простішe масштабувати великий код
- Менше прихованої магії дерева віджетів
- Зручніше працювати з async state
У сучасних Flutter-проєктах Riverpod часто вважається одним із найсильніших варіантів для довгострокової підтримки продукту.
57. Що таке Redux у Flutter?
Redux у Flutter - це підхід до керування станом із єдиним централізованим store, де стан змінюється через actions і reducers.
- Store - єдине джерело істини
- Action - опис наміру змінити стан
- Reducer - функція, яка обчислює новий state
- Middleware - місце для async логіки та side effects
- Прогнозований data flow
- Централізований state
- Прозорість змін
- Багато boilerplate
- Може бути надмірним для Flutter UI
- Часто програє сучаснішим підходам у зручності
Redux має історичну цінність і хорошу дисципліну, але в сучасних Flutter- проєктах його використовують рідше, ніж Riverpod, Provider або BLoC.
58. Що таке `ValueNotifier`?
ValueNotifier<T> - це простий реактивний клас у Flutter, який зберігає одне
значення і сповіщає слухачів, коли це значення змінюється.
final counter = ValueNotifier<int>(0);
counter.value++;- Простий локальний або screen-level state
- Мінімалістичні реактивні сценарії
- Коли не хочеться тягнути повноцінний state management
Найчастіше разом із ValueListenableBuilder.
ValueListenableBuilder<int>(
valueListenable: counter,
builder: (context, value, child) {
return Text('$value');
},
)ValueNotifier - хороший lightweight інструмент, якщо state простий і не
потребує складної архітектури.
59. Що таке `InheritedWidget`?
InheritedWidget - це базовий механізм Flutter для передачі даних вниз по
дереву віджетів і оновлення залежних віджетів при зміні цих даних.
- Поширення спільних даних у піддереві
- Доступ до залежностей через
BuildContext - Оптимізоване оновлення лише підписаних віджетів
ThemeMediaQueryDirectionalityProviderта інші бібліотеки під капотом
InheritedWidget - фундаментальний механізм Flutter. Навіть якщо команда не
пише його вручну, багато популярних бібліотек базуються саме на ньому.
60. У чому різниця між `Provider` і `InheritedWidget`?
InheritedWidget - це базовий механізм Flutter, а Provider - це зручна
бібліотечна абстракція поверх нього.
| Критерій | InheritedWidget |
Provider |
|---|---|---|
| Рівень | Низькорівневий базовий API | High-level abstraction |
| Зручність | Потрібно багато писати вручну | Значно простіше у використанні |
| Boilerplate | Більше | Менше |
| Масштабування | Незручно напряму для більшості команд | Краще для реальних застосунків |
- Якщо потрібне розуміння основ Flutter, треба знати
InheritedWidget - Якщо треба швидко і зручно будувати app-level state, частіше використовують
Provider
Provider не замінює концепцію InheritedWidget, а робить її зручнішою для
щоденної розробки.
61. Як працює навігація у Flutter?
Навігація у Flutter побудована навколо стеку маршрутів (routes). Коли користувач переходить на новий екран, новий route додається у стек, а при поверненні зі стека прибирається верхній route.
- Поточний екран є верхнім елементом стеку
- Новий перехід додає новий route
- Повернення видаляє верхній route
- Перехід вперед:
push - Повернення назад:
pop
- Imperative navigation через
Navigator - Named routes
- Router API / declarative navigation
- Пакети на кшталт
go_routerабоauto_route
Для простих застосунків часто достатньо базового Navigator. Для великих
продуктів із deep links, web navigation і складним routing частіше обирають
router-based підхід.
62. Що таке `Navigator`?
Navigator - це core-механізм Flutter для керування переходами між екранами.
- Зберігає стек маршрутів
- Додає нові екрани
- Прибирає поточні екрани
- Повертає результат назад у попередній екран
Його можна уявити як стек сторінок, де остання відкрита сторінка є активною.
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const DetailsPage(),
),
);Navigator тісно пов'язаний із BuildContext, тому треба викликати його з
контексту, який має доступ до потрібного навігаційного дерева.
63. Що роблять методи `Navigator.push()` і `Navigator.pop()`?
Navigator.push() додає новий екран у стек навігації, а Navigator.pop()
повертає назад, видаляючи верхній екран зі стеку.
Відкриває новий route.
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => const DetailsPage(),
),
);Закриває поточний route.
Navigator.pop(context);pop() може повертати значення назад:
Navigator.pop(context, 'success');Це базові методи для навігації у більшості Flutter-застосунків і один із перших API, який потрібно впевнено знати на співбесіді.
64. Як передати дані між екранами у Flutter?
Дані між екранами у Flutter найчастіше передаються через конструктор route
екрана або через результат, який повертається назад із Navigator.pop().
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => DetailsPage(userId: '42'),
),
);class DetailsPage extends StatelessWidget {
final String userId;
const DetailsPage({super.key, required this.userId});
@override
Widget build(BuildContext context) {
return Text(userId);
}
}final result = await Navigator.push<String>(
context,
MaterialPageRoute(
builder: (_) => const DetailsPage(),
),
);І назад:
Navigator.pop(context, 'done');- Named routes arguments
- Global/app state
- State management через Provider, Riverpod, BLoC
Разові дані екран-до-екрана краще передавати явно через конструктор. Не варто для цього одразу тягнути глобальний state.
65. Що таке `ModalBottomSheet`?
ModalBottomSheet - це нижня модальна панель, яка з'являється поверх поточного
контенту і блокує взаємодію з фоном, поки не буде закрита.
- Дії над контентом
- Вибір опцій
- Фільтри
- Форми короткої взаємодії
showModalBottomSheet(
context: context,
builder: (context) {
return const Padding(
padding: EdgeInsets.all(16),
child: Text('Bottom Sheet'),
);
},
);- Це саме modal-компонент
- Його можна закрити жестом або через
Navigator.pop(context)
ModalBottomSheet часто використовують у mobile UI замість окремого екрана або
діалогу, коли потрібно дати швидку контекстну взаємодію.
66. Що таке тема (`Theme`) у Flutter?
Тема у Flutter - це централізований набір візуальних налаштувань застосунку: кольори, типографіка, стилі кнопок, input-полів, app bar та інших компонентів.
- Єдиний візуальний стиль
- Проста зміна дизайну в одному місці
- Підтримка light/dark mode
- Консистентність UI в усьому застосунку
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const HomePage(),
)final theme = Theme.of(context);У production-застосунках тема є важливою частиною design system, а не просто набором кольорів.
67. У чому різниця між Material і Cupertino віджетами?
Material і Cupertino - це два різні набори UI-компонентів у Flutter, які відповідають різним дизайн-системам платформ.
- Орієнтований на Google Material Design
- Частіше використовується як дефолтний підхід у Flutter
- Основні віджети:
MaterialApp,Scaffold,AppBar,ElevatedButton
- Орієнтований на Apple Human Interface Guidelines
- Дає iOS-style вигляд і поведінку
- Основні віджети:
CupertinoApp,CupertinoPageScaffold,CupertinoButton,CupertinoNavigationBar
| Критерій | Material | Cupertino |
|---|---|---|
| Дизайн | Google Material | Apple iOS style |
| Компоненти | Android-first style | iOS-first style |
| Типовий use case | Кросплатформений default UI | iOS-native feel |
Багато команд використовують Material як базу навіть для кросплатформених застосунків. Але якщо продукт хоче максимально нативне відчуття iOS, тоді Cupertino стає важливим.
68. Як реалізувати адаптивний інтерфейс у Flutter?
Адаптивний інтерфейс у Flutter реалізують через комбінацію responsive layout, гнучких віджетів і логіки, яка враховує розмір та особливості екрана.
LayoutBuilderMediaQueryExpanded/FlexibleWrapAspectRatio- Умовний рендеринг для різних breakpoint-ів
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 900) {
return const DesktopLayout();
}
if (constraints.maxWidth > 600) {
return const TabletLayout();
}
return const MobileLayout();
},
)- Не фіксувати все жорстко в пікселях
- Враховувати portrait і landscape
- Враховувати tablet, foldable, desktop і web
- Виносити breakpoint logic у зрозумілу структуру
Адаптивність у Flutter - це не один віджет, а дисципліна побудови layout так, щоб UI коректно масштабувався на різних форм-факторах.
69. Що таке `FittedBox`?
FittedBox - це віджет, який масштабує і позиціонує дочірній елемент так, щоб
він вписався у доступний простір відповідно до обраного fit.
- Масштабування тексту або іконок
- Адаптація контенту до контейнера
- Уникнення overflow у деяких layout-сценаріях
FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'Very long title',
style: TextStyle(fontSize: 32),
),
)FittedBox не "лікує" всі layout-проблеми. Його треба застосовувати тоді, коли
дійсно потрібне масштабування контенту, а не замість правильного управління
constraints.
Це корисний інструмент для edge cases у responsive UI, але не основа layout- архітектури.
70. Що таке ізоляти (Isolates) у Flutter?
Ізоляти (Isolates) у Dart/Flutter - це окремі одиниці виконання з власною пам'яттю та власним event loop.
На відміну від класичних threads зі спільною пам'яттю, isolates не ділять стан напряму між собою.
- Кожен isolate має свій heap
- Кожен isolate виконується незалежно
- Дані не шаряться напряму між isolate-ами
Такий підхід зменшує ризик race conditions і проблем зі спільною пам'яттю.
UI зазвичай працює в головному isolate. Важкі обчислення можна винести в інший isolate, щоб не блокувати інтерфейс.
71. Для чого використовуються ізоляти?
Ізоляти використовуються для винесення важких або довготривалих задач із головного isolate, де працює UI.
- Важкі обчислення
- Парсинг великих JSON
- Обробка файлів
- Шифрування або декодування даних
- CPU-intensive business logic
Якщо виконувати важку синхронну роботу в головному isolate, UI може почати лагати, пропускати кадри або "заморожуватися".
Ізоляти потрібні не для будь-якої async-операції, а саме для CPU-bound задач.
Для звичайних HTTP-запитів або I/O найчастіше достатньо Future та async/await.
72. Як ізоляти взаємодіють між собою?
Ізоляти взаємодіють між собою через передачу повідомлень, а не через спільну пам'ять.
SendPort- для відправки повідомленьReceivePort- для отримання повідомлень
Один isolate надсилає дані іншому isolate-у у вигляді message passing.
- isolates не можуть напряму змінювати спільний об'єкт
- дані передаються через серіалізовані або transferable повідомлення
Ця модель складніша за звичайні async-виклики, але робить паралельне виконання безпечнішим і більш передбачуваним.
73. Які типи Streams існують у Dart?
У Dart найчастіше виділяють два основні типи streams: single-subscription та broadcast streams.
Такий stream призначений для одного слухача.
- Має одного subscriber-а
- Підходить для послідовного потоку даних
- Часто використовується для file I/O або async data pipelines
Такий stream дозволяє кільком слухачам підписуватися одночасно.
- Має багато subscriber-ів
- Підходить для подій
- Схожий на event bus / signal source
Якщо джерело даних має одного споживача, зазвичай достатньо single-subscription stream. Якщо потрібно розсилати події кільком слухачам, використовують broadcast stream.
74. Що таке `FutureBuilder`?
FutureBuilder - це Flutter-віджет, який будує UI на основі стану Future.
- Показ завантаження
- Показ успішного результату
- Показ помилки
FutureBuilder<String>(
future: fetchUserName(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text(snapshot.data ?? '');
},
)connectionStatehasDatahasErrordataerror
Не варто створювати Future прямо всередині build() без потреби, інакше він
може запускатися повторно при кожному rebuild.
75. Що таке `StreamBuilder`?
StreamBuilder - це Flutter-віджет, який будує UI на основі значень, що
надходять зі Stream.
FutureBuilderпрацює з одноразовим результатомStreamBuilderпрацює з потоком оновлень у часі
StreamBuilder<int>(
stream: counterStream(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
return Text('Value: ${snapshot.data}');
},
)- WebSocket updates
- Live data
- BLoC state streams
- Реактивні події
StreamBuilder зручний для реактивного UI, але важливо контролювати життєвий
цикл stream-ів, щоб не отримувати зайві підписки або memory leaks.
76. Як працюють анімації у Flutter?
Анімації у Flutter працюють через послідовну зміну значень у часі та перемальовування UI на кожному кадрі.
- Є початкове значення
- Є кінцеве значення
- Flutter обчислює проміжні стани
- UI оновлюється кадр за кадром
AnimationController- керує часом анімаціїTween- задає діапазон значеньCurvedAnimation- задає криву руху- Builder або Animated widget - оновлює UI
- Implicit animations - прості анімації без ручного контролю
- Explicit animations - повний контроль через controller
Flutter має дуже сильну animation system, бо UI малюється власним rendering engine, і це дає багато гнучкості для smooth transitions та custom motion.
77. Що таке `AnimationController`?
AnimationController - це об'єкт, який керує життєвим циклом explicit
анімації: запуском, зупинкою, реверсом і поточним прогресом.
- Зберігає тривалість анімації
- Рухається по шкалі значень, зазвичай від
0.0до1.0 - Дає змогу запускати
forward(),reverse(),repeat()
late final AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
}AnimationController зазвичай треба dispose()-ити, інакше можна отримати
витік ресурсів.
78. Що таке Tween-анімація?
Tween-анімація - це анімація, у якій значення плавно змінюється між двома
точками: begin і end.
Tween описує, як саме інтерполювати значення.
final animation = Tween<double>(
begin: 0,
end: 100,
).animate(controller);- Числа
- Кольори
- Відступи
- Розміри
- Alignment
Tween не запускає анімацію сам по собі. Він лише описує перехід значень, а
рухає цей перехід AnimationController.
79. Що таке `vsync`?
vsync - це механізм синхронізації анімації з частотою оновлення екрана.
- Щоб не рахувати кадри, коли віджет не видно
- Щоб зменшити зайве навантаження
- Щоб анімації були синхронізовані з rendering pipeline
У State часто використовують SingleTickerProviderStateMixin і передають
this у AnimationController.
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);Без vsync анімації могли б продовжувати працювати навіть тоді, коли їх не
треба рендерити, що погіршує продуктивність.
80. Що таке ticker у Flutter?
Ticker у Flutter - це об'єкт, який генерує callback на кожен кадр анімації.
- Повідомляє про кожен frame
- Дає змогу просувати анімацію в часі
- Використовується всередині
AnimationController
Ticker - це "метроном" для анімації.
Коли ви працюєте з AnimationController, ви майже завжди опосередковано
працюєте і з ticker.
81. Що таке `AnimatedBuilder`?
AnimatedBuilder - це віджет, який перебудовує частину UI у відповідь на зміни
анімованого значення.
- Реагувати на
Animation - Оновлювати лише потрібну частину UI
- Будувати explicit animations без зайвого boilerplate
AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Transform.scale(
scale: controller.value,
child: child,
);
},
child: const FlutterLogo(),
)Можна передати child, який не буде перебудовуватися на кожному кадрі.
82. Що таке `AnimatedContainer`?
AnimatedContainer - це віджет для implicit animation, який автоматично
анімує зміни своїх властивостей.
- Розмір
- Колір
- Padding
- Margin
- Alignment
- Decoration
AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: isExpanded ? 200 : 100,
color: isExpanded ? Colors.blue : Colors.red,
)AnimatedContainer - один із найзручніших способів швидко додати плавний UI
без ручного керування controller-ами.
83. У чому різниця між implicit та explicit анімаціями?
Різниця між implicit та explicit animation полягає в рівні контролю.
Flutter сам керує анімацією, коли змінюються властивості віджета.
AnimatedContainerAnimatedOpacityAnimatedAlign
Розробник сам керує анімацією через AnimationController.
AnimatedBuilderFadeTransitionScaleTransition
| Критерій | Implicit animations | Explicit animations |
|---|---|---|
| Контроль | Менший | Повний |
| Складність | Нижча | Вища |
| Use case | Прості UI transitions | Складні кастомні сценарії |
Для простих анімацій краще починати з implicit widgets. Для складних motion сценаріїв і синхронізації кількох анімацій потрібні explicit animations.
84. Що таке архітектура Flutter?
Архітектура Flutter складається з кількох ключових шарів: framework, engine, embedder і платформа.
- Framework - віджети, rendering, gestures, animation, foundation
- Engine - рендеринг, текст, compositing, Skia/graphics integration
- Embedder - інтеграція з Android, iOS, desktop або web
- Platform - нативна ОС та її API
Flutter не просто обгортає нативні UI-компоненти, а будує свій UI стек зверху вниз.
Саме через цю архітектуру Flutter дає високу консистентність UI між платформами, але інколи вимагає окремої інтеграції з нативним кодом.
85. Що таке rendering pipeline у Flutter?
Rendering pipeline у Flutter - це послідовність етапів, через які проходить UI від зміни state до відображення кадру на екрані.
- State change
- Build
- Layout
- Paint
- Compositing
- Rasterization
buildформує widget treelayoutрахує розміри та позиціїpaintмалює візуальний результат- engine перетворює це в кадр
Розуміння rendering pipeline допомагає дебажити jank, зайві rebuild-і, перефарбування та проблеми продуктивності.
86. Що таке Widgets, Elements і RenderObjects?
Це три ключові рівні UI-моделі Flutter.
Widgets - це immutable конфігурації UI.
Elements - це "живі" зв'язки між widget tree та render tree.
RenderObjects відповідають за layout, paint і low-level rendering.
- Widget - що ми хочемо показати
- Element - зв'язок і життєвий цикл у дереві
- RenderObject - як це реально вимірюється і малюється
Ця модель пояснює, чому Flutter може ефективно оновлювати UI, не перебудовуючи все заново на низькому рівні.
87. Що таке `FlutterEngine`?
FlutterEngine - це низькорівнева частина Flutter, яка відповідає за виконання
Dart-коду та рендеринг кадрів.
- Dart runtime
- Рендеринг
- Text layout
- Compositing
- Платформену взаємодію на низькому рівні
Framework дає зручний API для віджетів, а engine відповідає за те, щоб це реально працювало на екрані пристрою.
88. Що таке `WidgetsBinding`?
WidgetsBinding - це binding-шар, який з'єднує Flutter framework із engine та
координує життєвий цикл застосунку на рівні віджетів.
- Ініціалізація framework
- Робота з frame callbacks
- Доступ до binding lifecycle
- Координація між framework і engine
WidgetsFlutterBinding.ensureInitialized();Це один із центральних механізмів Flutter runtime, навіть якщо в типовому коді розробник бачить його лише опосередковано.
89. Що таке `WidgetsBindingObserver`?
WidgetsBindingObserver - це інтерфейс, який дозволяє слухати зміни життєвого
циклу застосунку та інші framework events.
- Відстеження
AppLifecycleState - Реакція на
resumed,paused,inactive,detached - Обробка platform-level змін
- зупинити відео, коли застосунок іде у background
- оновити дані, коли застосунок повертається у foreground
Це важливий інструмент для життєвого циклу, особливо у застосунках із медіа, аналітикою, socket-з'єднаннями або background-sensitive логікою.
90. Що таке platform channels?
Platform channels - це механізм взаємодії між Flutter-кодом на Dart і нативним кодом платформи, таким як Kotlin/Java на Android або Swift/Objective-C на iOS.
- Доступ до нативних API
- Робота з платформеними SDK
- Інтеграція з функціоналом, якого немає у Flutter напряму
MethodChannelEventChannelBasicMessageChannel
Platform channels потрібні тоді, коли Flutter-додаток виходить за межі чистого UI і має взаємодіяти з нативними можливостями пристрою або сторонніми SDK.
91. Що таке tree shaking?
Tree shaking - це процес видалення невикористовуваного коду з фінального build.
Якщо певний код не використовується, компілятор або білд-система не включає його в релізну збірку.
- Менший розмір застосунку
- Швидше завантаження
- Менше зайвого коду в production
Tree shaking особливо важливий для release build-ів, бо він допомагає зменшити розмір артефактів і покращити ефективність доставки застосунку.
92. Як оптимізувати продуктивність застосунку Flutter?
Оптимізація продуктивності у Flutter зводиться до зменшення зайвих rebuild-ів, repaint-ів, дорогих обчислень на UI isolate та надмірного споживання пам'яті.
- Зменшувати кількість непотрібних rebuild-ів
- Не виконувати важкі CPU-bound задачі в головному isolate
- Використовувати ліниві списки
- Використовувати
const, де це можливо - Оптимізувати зображення і ресурси
- Профілювати застосунок у profile mode
- Flutter DevTools
- Performance overlay
- Timeline profiling
- Memory profiler
Продуктивність у Flutter треба не "вгадувати", а вимірювати. Хороша оптимізація майже завжди починається з профілювання, а не з випадкових змін.
93. Як зменшити кількість перебудов віджетів?
Щоб зменшити кількість rebuild-ів, потрібно локалізувати state і перебудовувати лише ті частини дерева, які справді залежать від змін.
- Виносити UI у дрібніші віджети
- Використовувати
const - Локалізувати state якомога нижче
- Не слухати зайві глобальні стани
- Використовувати selector-підходи (
select, selectors, derived state)
Якщо змінюється лише badge у header, не треба перебудовувати весь екран.
Rebuild сам по собі не завжди проблема. Проблема виникає тоді, коли rebuild дорогий або відбувається занадто часто.
94. Що таке `RepaintBoundary`?
RepaintBoundary - це віджет, який відокремлює частину render tree в окрему
область перефарбування.
- Щоб не перефарбовувати весь екран
- Щоб ізолювати expensive paint-ділянки
- Щоб покращити продуктивність у складному UI
Якщо одна частина дерева часто змінюється, а інша ні, RepaintBoundary може
допомогти зменшити зайві repaint-и.
Його не варто додавати всюди бездумно. Як і будь-яка оптимізація, він має сенс там, де профілювання показало реальну repaint-проблему.
95. Як зменшити розмір застосунку Flutter?
Розмір Flutter-застосунку зменшують через оптимізацію залежностей, ресурсів та release build конфігурації.
- Видаляти непотрібні пакети
- Оптимізувати assets і зображення
- Використовувати tree shaking
- Не тягнути великі SDK без потреби
- Мінімізувати кількість шрифтів і локалей
- збирати release, а не debug
- аналізувати склад білду
- перевіряти, які пакети додають вагу
Розмір застосунку часто збільшується не через Flutter як такий, а через надлишкові ресурси, SDK та сторонні залежності.
96. Які best practices для великих Flutter застосунків?
Для великих Flutter-застосунків ключові best practices пов'язані з архітектурою, модульністю, тестованістю і дисципліною роботи зі станом.
- Feature-based або layered структура проєкту
- Чітке розділення UI, domain і data layer
- Прозорий state management
- Dependency injection
- Покриття тестами критичної логіки
- Єдина design system / theme system
- Логування, аналітика, error reporting
- уникати god-classes
- не змішувати network, UI і business logic в одному місці
- стандартизувати підходи команди
Великий Flutter-застосунок майже завжди програє без архітектурної дисципліни, навіть якщо стартував як "простий мобільний клієнт".
97. Які типи тестування існують у Flutter?
У Flutter найчастіше використовують три основні типи тестування.
Тестують окремі функції, сервіси, use cases, business logic.
Тестують окремі віджети і їхню поведінку в ізольованому середовищі.
Тестують реальні user flows у майже повному застосунку.
Здорова тестова стратегія зазвичай комбінує всі три типи, а не покладається лише на один.
98. Що таке unit testing?
Unit testing - це тестування маленьких ізольованих одиниць коду без UI і без залежності від реального застосунку.
- Функції
- Сервіси
- Use cases
- Парсинг
- Валідацію
- Швидке виконання
- Дешевий дебаг
- Добре підходить для бізнес-логіки
Якщо логіку можна протестувати без Flutter UI, це часто найстабільніший і найдешевший тип тестування.
99. Що таке widget testing?
Widget testing - це тестування віджетів Flutter у контрольованому середовищі без запуску повного застосунку на реальному пристрої.
- Що віджет відображає
- Як реагує на user interaction
- Чи змінюється UI після дії
- натиснути кнопку
- перевірити, що з'явився новий текст
Widget tests дають хороший баланс між швидкістю і цінністю, тому у Flutter їх часто вважають одним із найкорисніших типів тестів.
100. Що таке integration testing?
Integration testing - це тестування повних або майже повних user flows у застосунку.
- Взаємодія кількох екранів
- Навігація
- Робота з реальними сервісами або їхніми близькими замінами
- Повна поведінка користувацького сценарію
- логін
- відкриття списку
- перехід у деталі
- завершення дії користувача
Integration tests повільніші, крихкіші і дорожчі за unit та widget tests, тому ними зазвичай покривають саме критичні сценарії.
101. Як протестувати окремий віджет у Flutter?
Окремий віджет у Flutter зазвичай тестують через widget test із використанням
testWidgets, WidgetTester і pumpWidget().
testWidgets('counter increments smoke test', (WidgetTester tester) async {
await tester.pumpWidget(const MaterialApp(
home: CounterPage(),
));
expect(find.text('0'), findsOneWidget);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump();
expect(find.text('1'), findsOneWidget);
});- Побудувати віджет через
pumpWidget() - Знайти елементи через
find - Виконати interaction
- Перевірити очікуваний результат
Для більшості UI-компонентів це базовий і правильний спосіб перевірки поведінки.
102. Як виконувати HTTP-запити у Flutter?
HTTP-запити у Flutter зазвичай виконують через пакети на кшталт http або
dio.
- Пакет
http- простий базовий варіант - Пакет
dio- більш потужний варіант із interceptors, retries і config
final response = await http.get(
Uri.parse('https://example.com/api/users'),
);- окремий API client
- моделі даних
- error handling
- timeout/retry strategy
- логування запитів
Сам виклик HTTP простий, але production-ready networking - це вже окрема архітектурна зона застосунку.
103. Які бази даних можна використовувати з Flutter?
З Flutter можна використовувати кілька типів локальних і віддалених баз даних.
- SQLite
- Hive
- Isar
- SharedPreferences / key-value storage
- Firebase Firestore
- Supabase / PostgreSQL-backed services
- Будь-який backend із REST або GraphQL API
- Hive / Isar - швидке локальне сховище
- SQLite - структуровані локальні дані
- Firestore - real-time cloud data
Вибір бази залежить не від Flutter, а від моделі даних, offline-first вимог, синхронізації та складності домену.
104. Що таке Flutter plugins?
Flutter plugins - це пакети, які надають Flutter API для доступу до нативних можливостей платформи.
- Доступ до камери
- Доступ до геолокації
- Push notifications
- Bluetooth, sensors, storage, permissions
Плагін має Dart API і платформені реалізації для Android, iOS та інколи інших платформ.
Plugins дозволяють не писати platform channels вручну щоразу, а використовувати готову інтеграцію.
105. Як інтегрувати Flutter у вже існуючий нативний застосунок?
Flutter можна інтегрувати в існуючий Android або iOS застосунок як окремий модуль.
Flutter не обов'язково має бути "весь застосунок". Його можна вбудувати лише в окремі екрани або фічі.
- Створюється Flutter module
- Нативний застосунок підключає цей модуль
- Певні екрани відкриваються через
FlutterActivity,FlutterFragmentабо iOS integration
- поступова міграція нативного застосунку на Flutter
- запуск нової фічі на Flutter без повного переписування
Add-to-app підхід корисний тоді, коли бізнес не готовий переписати все, але хоче поступово використати Flutter у продукті.
106. Як реалізувати платформо-залежний код у Flutter?
Платформо-залежний код у Flutter реалізують кількома способами залежно від рівня задачі.
- Platform channels - коли потрібен нативний код
- Готові plugins - коли вже є пакет для потрібної функції
Platform.isAndroid/Platform.isIOS- для платформних гілок логікиdefaultTargetPlatform- для UI-поведінки
if (Platform.isIOS) {
// iOS-specific logic
} else if (Platform.isAndroid) {
// Android-specific logic
}Якщо є готовий перевірений plugin, краще використовувати його. Якщо немає, тоді вже писати platform channel або власний plugin.