Flutter体验 Day 19-InheritedWidget

功能组件-InheritedWidget

InheritedWidget是一个具有特殊功能的组件,它提供可以将资料从 widget 从上到下传递的功能,达到共享数据的目的,其重要性与 StatelessWidgetStatefulWidget 相当。

我们在MaterialApp可以使用ThemeData定义App整体的风格,

Theme 使用案件

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      theme: ThemeData(
        primaryColor: Colors.green,
        accentColor: Colors.yellow[300],
        textTheme: const TextTheme(
          headline6: TextStyle(fontSize: 24.0, fontStyle: FontStyle.italic),
        ),
      ),
      initialRoute: '/',
      routes: {
        '/': (context) => HomeScreen(),
        '/theme': (context) => ThemeScreen(),
      },
    );
  }
}

在底层的 widget 可以使用 Theme.of(context) 的方法取得上层的共享资料

class ThemeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Button")),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            color: Theme.of(context).accentColor,
            child: Text(
              '使用来自 MaterialApp 设定的 ThemeData',
              style: Theme.of(context).textTheme.headline6,
            ),
          ),
        ],
      ),
    );
  }
}

InheritedWidget 实作

Flutter 习惯使用名称为 of 的静态方法,定义 InheritedWidget 功能组件的使用,其应用 BuildContextdependOnInheritedWidgetOfExactType方法从 Element Tree 向父层寻找符合 MyThemeWidget 型态的资源。

让我们使用 InheritedWidget 实作 MyThemeWidget,共享自己定义的 MyThemeData 样式资料。

class MyThemeData {
  final Color? primaryColor;
  MyThemeData({this.primaryColor});
  MyThemeData.fallback() : this(primaryColor: Colors.blue);
}

class MyThemeWidget extends InheritedWidget {
  final MyThemeData? data;
  MyThemeWidget({required Widget child, this.data}) : super(child: child);

  @override
  bool updateShouldNotify(MyThemeWidget oldWidget) {
    return oldWidget.data != data;
  }

  static MyThemeData of(BuildContext context) {
    final MyThemeWidget? _inheritedTheme =
        context.dependOnInheritedWidgetOfExactType<MyThemeWidget>();
    MyThemeData theme = _inheritedTheme?.data ?? MyThemeData.fallback();
    return theme;
  }
}

范例中我们使用 Switch 模拟 MyThemeData 资料变更的状况

class MyThemeBox extends StatefulWidget {
  _MyThemeBoxState createState() => _MyThemeBoxState();
}

class _MyThemeBoxState extends State<MyThemeBox> {
  bool toggle = false;
  Widget build(BuildContext context) {
    var color;
    if (toggle) {
      color = Colors.red;
    } else {
      color = Colors.blue;
    }
    return MyThemeWidget(
      data: MyThemeData(primaryColor: color),
      child: Container(
        child: Column(
          children: [
            Switch(
              value: toggle,
              onChanged: (bool value) {
                setState(() {
                  toggle = value;
                });
              },
            ),
            TextLabel(),
          ],
        ),
      ),
    );
  }
}

这边是我们在 MyThemeWidget 底层的组件,可通过of取得 MyThemeData 资料。

还记得当初在谈 State 生命周期的时候有提到 didChangeDependencies 的触发与是否有使用 InheritedWidget 内的资料有关。

class TextLabel extends StatefulWidget {
  _TextLabelState createState() => _TextLabelState();
}

class _TextLabelState extends State<TextLabel> {
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print("didChangeDependencies()");
  }

  @override
  Widget build(BuildContext context) {
    var primaryColor = MyThemeWidget.of(context).primaryColor;

    return Text(
      "使用来自 MyThemeWidget 设定的 MyThemeData",
      style: TextStyle(color: primaryColor),
    );
  }
}

今日成果

程序码

widget_theme


<<:  day 19 - health check 让k8s帮忙关怀服务

>>:  Ruby on Rails 语言

Day6 Android - 元件使用(EditText->Button->TextView)

今天主要要来介绍这三个元件及彼此之间一个简单的应用,首先先来提一下EditText、textView...

[day-19] 认识Python的资料结构!(Part .6)

再熟悉不过的字串,也算是资料结构?   我们常常使用的字串,也算是一种有顺序关系的「序列容器」,因此...

Flutter基础介绍与实作-Day17 Onboarding、Login、Sign Up范例实作(4)

今天就废话不多说把注册页写完吧! 注册页 一样先来构思画面,由上而下AppBar,标题,描述文字,e...

Day10 - 套用 Tag Helper - 复杂型别 object

这篇开始使用 Tag Helper 来 Render 出需要的 Html 控制项 name,方便在 ...

【第二十天 - Flutter 与 Android、iOS 沟通方式 - 官方范例讲解】

前言 这篇,想要介绍一下 Flutter 如何把某些功能打包给原生的 Android、Ios 写。将...