Flutter .of(context)

Егор Долгов · 02.08.2019
This article was written for an older Flutter version and is being updated. Some code may not compile on the current version.

Для обращения к ближайшему родительскому объекту данного класса исходя из контекста, можно с помощью конструкции .of(context) .

В этом примере, на верхнем уровне у нас будет виджет TopScreen . Он будет задавать общий фон, но менять фон мы будем из дочернего виджета - по нажатию на одну из кнопок. Мы сможем обращаться к параметру TopScreen.of(context). color и к методу TopScreen.of(context).setState((){}) .

Описание классов TopScreen и TopScreenState

class TopScreen extends StatefulWidget {
  final Widget child; // дочерний виджет

  TopScreen({this.child});

  @override
  State createState() => _TopScreenState();

  static _TopScreenState of(BuildContext context) {
    // Эта конструкция нужна, чтобы можно было обращаться к нашему виджету
    // через: TopScreen.of(context)
    assert(context != null);
    final _TopScreenState result =
        context.ancestorStateOfType(const TypeMatcher<_TopScreenState>());
    return result;
  }
}

class _TopScreenState extends State {
  Color _color = Colors.green; // цвет фона
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: AnimatedContainer( // используем это виджет для анимации цвета фона
      child: widget.child, // обращение к дочернему виджету TopScreen через widget.child
      color: _color,
      duration: Duration(milliseconds: 500), // длительность анимации
    ));
  }
}

Остальная часть программы

import 'package:flutter_web/material.dart';

void main() => runApp(MaterialApp(home: TopScreen(child: MainScreen())));

class MainScreen extends StatefulWidget {
  @override
  State createState() => MainScreenState();
} //MainScreen

class MainScreenState extends State {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          MaterialButton(
            child: Text('red'),
            color: Colors.red,
            onPressed: () {
              TopScreen.of(context)._color = Colors.red; // Изменяем цвет фона напрямую.
              // ВНИМАНИЕ: Изменять параметр объекта напрямую не правильно для ООП!
              // Это только пример, в реализации лучше сделать сеттер или метод для изменения.
              TopScreen.of(context).setState(() {}); // Вызов метода смены состояния родительского виджета.
            },
          ),
          MaterialButton( // Все тоже самое что и для кнопки выше.
            child: Text('green'),
            color: Colors.green,
            onPressed: () {
              TopScreen.of(context)._color = Colors.green;
              TopScreen.of(context).setState(() {});
            },
          ),
          MaterialButton( // Все тоже самое что и для кнопки выше.
            child: Text('blue'),
            color: Colors.blue,
            onPressed: () {
              TopScreen.of(context)._color = Colors.blue;
              TopScreen.of(context).setState(() {});
            },
          ),
        ],
      ),
    );
  } //build
} //MainScreenStat