Основи Flutter
В першій частині я розповів постановку задачі. Тепер переходжу до опису процессу розробки.
Dart
Flutter - все є віджет
Заголовок підрозділу - це основна концепція Flutter. Наприклад, є віджет для відображення тексту:
Text('Copyright(c) 2021 Vadym A. Khokhlov')
Якщо необхідно додати навколо тексту відступи, ми вставляємо його у віджет Padding:
Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('Copyright(c) 2021 Vadym A. Khokhlov'),
),
Программа - це теж віджет. Ось, наприклад, як зазвичай виглядає початок:
void main() {
runApp(NumberFactsApp());
}
class NumberFactsApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Facts about numbers',
home: const NumberFactsScreen(),
);
}
}
Функція main запускає віджет NumberFactsApp як головний віджет програми. Він має обов'язково реалізувати метод build для своєї побудови. Цей метод повертає інший віджет - MaterialApp, якому в якості аргументу home треба вказати ще один віджет - в данному випадку NumberFactsScreen. Таким чином програма представляє собою дерево віджетів. Насправді дерев три: Widgets, Elements, RenderObjects. Але програмісти в основному працюють саме з першим.
Стан віджета
Flutter надає крила два основних класа віджетів: stateless та statefull.
Якщо вигляд віджету не від чого не залежить, то він утворюється як підклас StatelessWidget. Приклад - наведений вище NumberFactsApp.
Якщо ж віджет має змінювати вигляд у відповідь на дії користувача або залежить ще від якіхось факторів, то він утворюється як підкласс StatefulWidget. Такі віджети зберігають свій стан в об'єкті окремого класу, підкласу State. Ось приклад віджету, що дозволяє користувачеві вибирати мову, на якій будуть відображатись факти:
class _LangSelector extends StatefulWidget {
...
@override
__LangSelectorState createState() => __LangSelectorState();
}
class __LangSelectorState extends State<_LangSelector> {
final LangsService langsService = serviceLocator<LangsService>();
@override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
setState(() {
_curLangIndex = 1 - _curLangIndex;
...
});
},
child: Text(langsService.flag(_curLangIndex)));
}
int _curLangIndex = 0;
}
Для того, щоб повідомити Flutter, що стан віджету змінився і його необхідно перебудувати використвується метод setState. Одна з особливостей Dart полягає в тому, що в ній немає якогось слова для позначення приватних методів або змінних. Замість цього достатньо ім'я розпочати з _. (Про langsService я розповім пізніше).
Звісно, що змішувати в одному класі і логіку роботи віджета, і опис його вигляду - погана ідея. Тому у Flutter використовуються механізми керування станом (state management), що дозволяют відокремити логіку від інтерфейсу. У наступних статтях я розповім про один з них. Хоча свою першу гру я написав без використання таких механізмів. Але я стидаюсь показати її код :)
Документація по widget'ам Flutter тут.