Flutter: что такое Context
Всем привет, меня зовут Даниил! И я Flutter разработчик в компании AppVesto.
В этой статье мы разберемся что из себя представляет context и как его правильно использовать.
Что такое Widget
Чтобы убедиться, что мы на одной волне, давайте начнем с понятия Widget. Наверняка, вы слышали такую фразу: «Все во Flutter — это виджеты.» Однако, это не совсем правильно.
Корректнее будет сказать, что виджеты — это все, что отображается на экране. Общий макет страницы, положение и размер кнопки, цвет и размер текста — все это создано с использованием виджетов.
Что такое дерево виджетов
Виджеты во Flutter имеют иерархическую структуру или, иными словами, виджеты организованы в виде дерева.
- Виджет, который содержит в себе другие виджеты называется родительским виджетом или parent Widget.
- Виджеты, которые хранятся в родительском виджете, называются дочерними или children Widgets.
Рассмотрим небольшой пример стандартного кода, который автоматически генерируется при создании нового проекта.
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); }
Виджет Scaffold является родительским виджетом для Center, а Center, в свою очередь, является родительским для Column. Соответственно, Column — это дочерний виджет Center.
Как создать виджет
Для создания любого виджета используется метод build, который принимает в качестве аргумента BuildContext.
BuildContext — это описание позиции виджета в дереве виджетов. Именно этот класс описывает отношение parent-children и позволяет реализовать такие функции как showDialog, Theme.of и некоторые другие функции, которые позволяют использовать контекст родительского виджета, например его размеры и местоположение.
BuildContext используется, чтобы избежать прямого манипулирования родительским виджетом и получить необходимую информацию, которая содержится в родительском контексте.
Что вам необходимо знать о context
- Context — это ссылка на расположение виджета в древовидной структуре виджетов.
- Контекст может принадлежать только одному виджету.
- Если у виджета есть дочерние виджеты, то контекст родительского виджета становится родительским контекстом для контекстов прямых дочерних элементов.
- Виджет виден только в его собственном контексте или в контексте его родительского контекста.
Таким образом, становится понятно, что зная дочерний контекст, можно легко найти родительский виджет. И наоборот, с помощью родительского контекста можно найти дочерний виджет.
Метод ‘of()’
Как мы уже знаем, виджеты во Flutter имеют структуру дерева и могут общаться с другими виджетами, находящимися как ниже, так и выше по дереву виджетов.
«Общение» виджетов между собой обеспечивается методом Of().
Давайте рассмотрим небольшой пример:
@override Widget build(context) { return Text('Subscribe to the AppVesto Instagram!', style: TextStyle(color: Theme.of(context).primaryColor), ); }
Метод of() ищет в дереве виджетов родительский виджет, который имеет тип Theme, и использует его свойство primaryColor для текущего виджета.
Это возможно благодаря тому, что Flutter знает положение объекта Theme в дереве по отношению к текущему buildContext.
Метод of() может быть полезен для решения многих задач, например для получения размера экрана с помощью MediaQuery.of(context) или навигации с помощью Navigator.of(context). Для создания некоторых виджетов, таких как snackBar нужно использовать ближайший контекст Scaffold, чтобы Flutter мог его корректно отрисовать на экране.
При выполнении следующего кода вы получите ошибку: «Scaffold.of() called with a context that does not contain a Scaffold».
Пример (Не работает):
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: RaisedButton( child: Text('Show Snack Bar'), onPressed: () { Scaffold.of(context).showSnackBar( SnackBar( backgroundColor: Colors.blue, content: Text('I am SNACKBAR!!!'), ), ); }, ), ), ); }
Данный код не работает потому что виджет Scaffold еще не создан, а контекст который был передан в метод build указывает на родителя который не содержит Scaffold.
Итак, как же предоставить дочернему виджету snackBar доступ к родительскому виджету Scaffold?
Для того чтобы исправить возникшую проблему, обернем кнопку виджетом Builder и все заработает:
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Builder( builder: (BuildContext context) { return RaisedButton( child: Text('Show Snack Bar'), onPressed: () { Scaffold.of(context).showSnackBar( SnackBar( backgroundColor: Colors.blue, content: Text('I am SNACKBAR!!!'), ), ); }, ); }, ), ), ); }
Builder позволяет получить и использовать контекст виджета в котором находится сам Builder. В примере выше это виджет Scaffold.
Если у вас остались какие-то вопросы, задавайте их в комментариях и я с радостью на них отвечу.
10 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів