Как правило, при создании приложения новые виджеты обычно определяются как подклассы либо класса StatelessWidget, либо класса StatefulWidget. В чем разница между ними?
Виджеты бывают двух видов: stateful (имеют состояние) и stateless (не имеют состояния).
Виджеты, которые не имеют состояния, (stateless) в процессе работы приложения не изменяют своих свойств. Такие виджеты не имеют состояния. Они могут изменяться лишь посредством внешних событий, которые возникают на родительских виджетах-контейнерах. И класс StatelessWidget как раз представляет данный тип виджетов.
Виджеты, которые хранят состояние, (stateful) в процессе работы приложения могут изменять свои свойства динамически. Состояние хранится в виде объекта класса State. И класс StatefulWidget представляет виджеты, которые могут хранить состояние.
Вначале рассмотрим, как мы можем работать с классом StatelessWidget.
Этот класс подходит для создания виджетов, которые не хранят состояние. При создании своего подкласса необходимо переопределить метод build(). Этот метод используется для построения интерфейса и вызывается обычно в трех ситуациях:
когда виджет в первый раз добавляется в дерево виджетов, которое описывает пользовательский интерфейс
когда контейнер, в котором расположен подкласс StatelessWidget, меняет конфигурацию подкласса StatelessWidget
когда меняется объект InheritedWidget, от которого зависит подкласс StatelessWidget
Если контейнер часто меняет конфигурацию вложенного StatelessWidget, соответственно метод build()
будет
вызываться также часто. И в этой ситуации возможно потребуется оптимизировать вызов этого метода. Для этого можно
минимизировать количество виджетов, которые создаются в методе build()
. Еще одна техника в
использовании оператора const при определении виджетов, насколько это возможно, а также в
определении для виджетов константного конструктора.
Определение простейшего подкласса StatelessWidget:
class MyStatelessWidget extends StatelessWidget{ @override Widget build(BuildContext context) { return Container( color: Colors.white, ); } }
В качестве параметра в метод build()
передается объект BuildContext, который
содержит информацию о контексте виджета.
Метод build()
должен возвращать другой виджет. В данном случае он возвращает виджет Container.
Как использовать свой виджет? Создадим и используем простейший виджет:
import 'package:flutter/material.dart'; void main() { runApp(MyStatelessWidget()); } class MyStatelessWidget extends StatelessWidget{ @override Widget build(BuildContext context) { return Container( color: Colors.white, padding: EdgeInsets.only(top:40), child: const Text( "Hello Flutter from METANIT.COM", style: TextStyle(fontSize: 22, color: Colors.lightBlue), textAlign: TextAlign.center, textDirection: TextDirection.ltr, ), ); } }
В данном случае кастомный виджет содержит более сложную структуру - он содержит Container, который, в свою очередь, содержит виджет Text.
В методе runApp()
используем этот виджет в качестве главного контейнера для нашего приложения:
runApp(MyStatelessWidget());
В данном случае наш кастомный виджет выполняет роль контейнера, который содержит все остальные виджеты. Однако он может использоваться и в качестве вложенного элемента. Например:
import 'package:flutter/material.dart'; void main() { runApp(Container( color: Colors.white, padding: EdgeInsets.only(top:40), child: const MyStatelessWidget(), )); } class MyStatelessWidget extends StatelessWidget{ const MyStatelessWidget({ Key key }) : super(key: key); @override Widget build(BuildContext context) { return Text( "Hello Flutter!", style: TextStyle(fontSize: 22, color: Colors.lightBlue), textAlign: TextAlign.center, textDirection: TextDirection.ltr, ); } }
В данном случае виджет MyStatelessWidget выступает в качестве вложенного по отношению к элементу Container.
Стоит отметить, что здесь в виджете также определен константный конструктор. Его определение в принципе необязательно,
это лишь позволяет при использовании виджета применить оператор const
:
child: const MyStatelessWidget(),
В качестве параметра в конструктор передается параметр Key
, который передается далее в конструктор
базового класса StatelessWidget.
const MyStatelessWidget({ Key key }) : super(key: key);
При вызове виджета нам не надо в него передавать явным образом объект Key - этот объект передается системой.
Выше определенный конструктор фактически повторяет конструктор базового класса StatelessWidget. Однако мы можем определить и другие конструкторы при необходимости. Обычно конструкторы применяются для передачи в виджет извне некоторых данных. Например:
import 'package:flutter/material.dart'; void main() { runApp(Container( color: Colors.white, padding: EdgeInsets.only(top:40), child: const MyStatelessWidget(myText: "Flutter on metanit.com", myColor: Colors.redAccent), )); } class MyStatelessWidget extends StatelessWidget{ final String myText; final Color myColor; const MyStatelessWidget({ Key key, this.myText, this.myColor }) : super(key: key); @override Widget build(BuildContext context) { return Text( myText, style: TextStyle(fontSize: 22, color: myColor), textAlign: TextAlign.center, textDirection: TextDirection.ltr, ); } }
В данном случае в конструктор MyStatelessWidget также передается извне цвет и текст, которые затем используются для вывода текста.
Подобным образом мы можем задать и вложенные виджеты в подклассе StatelessWidget:
import 'package:flutter/material.dart'; void main() { runApp(Container( color: Colors.white, padding: EdgeInsets.only(top:25), child: const MyStatelessWidget( myColor: Colors.tealAccent, myChild: Text("Flutter на metanit.com", style: TextStyle(fontSize: 22, color: Colors.teal), textAlign: TextAlign.center, textDirection: TextDirection.ltr,), ), )); } class MyStatelessWidget extends StatelessWidget{ final Widget myChild; final Color myColor; const MyStatelessWidget({ Key key, this.myChild, this.myColor = Colors.white70}) : super(key: key); @override Widget build(BuildContext context) { return Container( color: myColor, child: myChild ); } }
В данном случае виджет, который будет содержаться во вложенном элементе Container, передается через свойство
myChild
.